with shade plugin compiler java maven jfreechart maven-shade-plugin

java - shade - Archivo JAR inválido o corrupto creado por el plugin de sombra Maven



maven-jar-plugin (3)

Después de agregar la dependencia de Maven jFree a mi aplicación existente, no puedo ejecutar el jar creado.

El único mensaje de error que recibo es el siguiente:

java -jar target/com.company.product-1.0.0-SNAPSHOT.jar Error: Invalid or corrupt jarfile target/com. company.product-1.0.0-SNAPSHOT.jar

El pom.xml completo se ve así:

<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion <groupId>com.mycompany</groupId> <artifactId>com.mycompany.test</artifactId> <name>${project.artifactId}</name> <version>1.0.0-SNAPSHOT</version> <properties> <java-version>1.7</java-version> <org.springframework-version>3.1.1.RELEASE</org.springframework-version> <org.springframework.data-version>1.0.3.RELEASE</org.springframework.data-version> <org.springframework.ws-version>2.0.4.RELEASE</org.springframework.ws-version> <org.springframework.ws.oxm-version>1.5.10</org.springframework.ws.oxm-version> <org.aspectj-version>1.6.12</org.aspectj-version> <org.slf4j-version>1.5.10</org.slf4j-version> <selenium-java-version>2.25.0</selenium-java-version> <browser-mob-version>2.0-beta-6</browser-mob-version> </properties> <dependencies> <!-- Hint A: If we delete this dependency it works --> <dependency> <groupId>org.jfree</groupId> <artifactId>jfreechart</artifactId> <version>1.0.14</version> <exclusions> <exclusion> <artifactId>itext</artifactId> <groupId>com.lowagie</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.3.2</version> </dependency> <dependency> <groupId>de.schlichtherle.io</groupId> <artifactId>truezip</artifactId> <version>6.6</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>apache-log4j-extras</artifactId> <version>1.1</version> </dependency> <!-- Caching with ehcache --> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.5.2</version> <type>pom</type> </dependency> <!-- Spring --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${org.springframework-version}</version> <exclusions> <!-- Exclude Commons Logging in favor of SLF4j --> <exclusion> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context-support</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${org.springframework-version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>3.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>3.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>3.0.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${org.springframework-version}</version> <scope>test</scope> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate.java-persistence</groupId> <artifactId>jpa-api</artifactId> <version>2.0-cr-1</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>3.5.1-Final</version> </dependency> <!-- Database Connectors (HSQL should be removed later) --> <dependency> <groupId>hsqldb</groupId> <artifactId>hsqldb</artifactId> <version>1.8.0.7</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.16</version> </dependency> <!-- AspectJ --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>${org.aspectj-version}</version> </dependency> <!-- Logging --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${org.slf4j-version}</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.16</version> </dependency> <!-- @Inject --> <dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>1.2</version> </dependency> <!-- Spring Data JPA dependencies --> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-jpa</artifactId> <version>${org.springframework.data-version}</version> </dependency> <dependency> <groupId>javax.ws.rs</groupId> <artifactId>jsr311-api</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-oxm</artifactId> <version>${org.springframework.ws.oxm-version}</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-xml</artifactId> <version>${org.springframework.ws-version}</version> </dependency> <dependency> <groupId>org.springframework.ws</groupId> <artifactId>spring-ws-core</artifactId> <version>${org.springframework.ws-version}</version> </dependency> <dependency> <groupId>javax.xml</groupId> <artifactId>jaxb-impl</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>javax.xml</groupId> <artifactId>jaxb-api</artifactId> <version>2.1</version> </dependency> <!-- Test --> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.7</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-all</artifactId> <version>1.9.0</version> <scope>test</scope> </dependency> <!-- Common Utils --> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>commons-cli</groupId> <artifactId>commons-cli</artifactId> <version>1.2</version> </dependency> <!-- Selenium --> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-java</artifactId> <version>${selenium-java-version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-firefox-driver</artifactId> <version>${selenium-java-version}</version> </dependency> <dependency> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-chrome-driver</artifactId> <version>${selenium-java-version}</version> </dependency> <!-- CSV Lib for Keyword Checker --> <dependency> <groupId>net.sf.opencsv</groupId> <artifactId>opencsv</artifactId> <version>2.0</version> </dependency> <!-- Google Places API --> <dependency> <groupId>com.google.api-client</groupId> <artifactId>google-api-client</artifactId> <version>1.10.3-beta</version> <exclusions> <exclusion> <artifactId>jackson-core-asl</artifactId> <groupId>org.codehaus.jackson</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>com.google.api-client</groupId> <artifactId>google-api-client-appengine</artifactId> <version>1.10.3-beta</version> </dependency> <dependency> <groupId>org.codehaus.jackson</groupId> <artifactId>jackson-mapper-asl</artifactId> <version>1.9.9</version> </dependency> <!-- Google Geocode --> <dependency> <groupId>com.google.code.geocoder-java</groupId> <artifactId>geocoder-java</artifactId> <version>0.9</version> </dependency> <dependency> <groupId>com.googlecode.json-simple</groupId> <artifactId>json-simple</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>com.googlecode.json-simple</groupId> <artifactId>json-simple</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>net.sf.jgrapht</groupId> <artifactId>jgrapht</artifactId> <version>0.8.3</version> </dependency> <dependency> <groupId>jgraph</groupId> <artifactId>jgraph</artifactId> <version>5.13.0.0</version> </dependency> <!-- Apache Http Client --> <dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.2.1</version> </dependency> <!-- Amazon web services client --> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk</artifactId> <version>1.2.15</version> <exclusions> <exclusion> <artifactId>jackson-core-asl</artifactId> <groupId>org.codehaus.jackson</groupId> </exclusion> </exclusions> </dependency> <!-- Docx4j - reading excel files --> <dependency> <groupId>org.docx4j</groupId> <artifactId>docx4j</artifactId> <version>2.8.0</version> </dependency> <!-- Browser Mob Proxy --> <dependency> <groupId>biz.neustar</groupId> <artifactId>browsermob-proxy</artifactId> <version>${browser-mob-version}</version> <exclusions> <exclusion> <groupId>org.seleniumhq.selenium</groupId> <artifactId>selenium-api</artifactId> </exclusion> <exclusion> <artifactId>icu4j</artifactId> <groupId>com.ibm.icu</groupId> </exclusion> <exclusion> <artifactId>jackson-mapper-asl</artifactId> <groupId>org.codehaus.jackson</groupId> </exclusion> <exclusion> <artifactId>jackson-core-asl</artifactId> <groupId>org.codehaus.jackson</groupId> </exclusion> <exclusion> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> </exclusion> </exclusions> </dependency> <!-- Hint B: If we copy this Apache POI dependencies to the top, it works --> <!-- Apache POI - for reading xlsx files --> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>poi-ooxml</artifactId> <version>3.8</version> </dependency> <dependency> <groupId>org.apache.xmlbeans</groupId> <artifactId>xmlbeans</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.apache.poi</groupId> <artifactId>ooxml-schemas</artifactId> <version>1.1</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>${java-version}</source> <target>${java-version}</target> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> <version>1.7</version> <executions> <execution> <phase>package</phase> <goals> <goal>shade</goal> </goals> <configuration> <transformers> <!-- must be SURE to do this with both spring.handlers and spring.schemas. otherwise you won''t be able to use them in the spring config files. --> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.handlers</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer"> <resource>META-INF/spring.schemas</resource> </transformer> <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"> <mainClass>com.mycompany.test.Start</mainClass> </transformer> </transformers> <filters> <filter> <artifact>bouncycastle:bcprov-jdk15</artifact> <excludes> <exclude>META-INF/BCKEY.DSA</exclude> <exclude>META-INF/BCKEY.SF</exclude> <exclude>META-INF/MANIFEST.MF</exclude> </excludes> </filter> </filters> </configuration> </execution> </executions> </plugin> </plugins> </build>

No obtengo ninguna otra información de depuración si ejecuto el jar.

¿Hay alguna opción para validar el archivo jar? ¿O tener algo como java -verbose ...?

Pasos para reproducir:

  1. crear una nueva carpeta
  2. Copie el Pom.xml de arriba en la carpeta.
  3. Guarde el pequeño `public static void main (...). en src / main / java / com / mycompany / test / Start.java
  4. ejecutar mvn clean package
  5. ejecutar java -jar target/com.mycompany.test-1.0.0-SNAPSHOT.jar

Anexo 1:

package com.mycompany.test; public class Start { public static void main(final String[] args) { System.out.println("If you are able to get this printed with java -jar you made it. Thanks a lot! :)"); } }

Editar 1:

Empecé a eliminar algunas dependencias para identificar el problema. Pero no tengo una comprensión clara de lo que sale mal.

Ahora descubrí (Ver sugerencia B en el pom.xml) que al mover las dependencias del POI de Apache a la parte superior se resolverá el problema. Pero aún no sé cómo y por qué es el problema.


Me pregunto si tienes más de una versión del jfree jar en tu proyecto y el plugin de sombra está recogiendo el incorrecto. ¿Has revisado el uber-jar para las clases de jfree y comparado con aquellos en el jfree jar que estás esperando que esté presente? Puede abrir el jar con winzip o equivalente.


Por mi parte, si construyo tu proyecto usando el pom.xml que nos has mostrado, con apache-poi declarado después de jfreechart , entonces, como has mencionado, obtengo un JAR corrupto. Intercambiar el orden de estas dos dependencias de hecho me da un JAR correcto.

Tengo alguna experiencia previa con maven-shade-plugin y cuando lo usé tuve problemas con el directorio creado de MET de JAR, así que lo he comprobado en busca de defectos.

Intenté copiar (utilizando Total Commander) el directorio META-INF algún lugar de mi sistema de archivos local y lo que noté es que hubo errores al copiar los archivos en META-INF/licences/ . Si intenté copiarlos en algún lugar de manera individual, funcionó, pero no pude copiar todo. Mi conclusión fue que el archivo JAR / ZIP está dañado.

Lo que hice fue ingresar ese JAR en Total Commander ( Ctrl + PgDown sobre el archivo JAR) y thirdpartylicenses.txt nombre de thirdpartylicenses.txt a thirdpartylicenses.txt.wtf . Al hacer esto, Total Commander ofrece guardarlo y vuelve a empaquetar el JAR (tengo instalado el plugin packer Total7zip Total Commander; si alguien lo intenta y no funciona, pruébalo con esto instalado).

Después de este. Funciona.

(También intenté volver a empaquetar todo sin renombrar nada con los comandos de unzip / zip Cygwin, pero eso no funcionó, el nuevo archivo todavía estaba dañado. Total Commander o el complemento que he mencionado hace algo de magia.)

Supongo que el maven-shade-plugin simplemente crea un archivo ZIP / JAR corrupto o no válido. No estoy seguro de por qué y tal vez lo que describí no funcionará para nadie más, pero pensé que lo mencionaría, así que tal vez podría ayudar.

No podía dejar esto solo, así que he profundizado y creo que encontré la respuesta.

El JAR incorrecto contiene 65608 entradas. El buen JAR contiene 65450 entradas.

Adivina cuál es el límite superior de la cantidad de entradas para un archivo ZIP simple Sí. El artículo de Wiki habla sobre un formato ZIP64 que supera esta limitación.

El JAR bueno tiene menos entradas porque las dependencias reales cambian debido a la posición de las declaraciones de dependencia en su pom.xml . ( Como se describe en esta respuesta ) .

He contado las entradas como esta.

Collections.list(new JarFile("...").entries()).size();

Estaba usando Java 7, que parece ser compatible con el nuevo formato ZIP64 , por lo que tal vez, si alguien intenta contar las entradas en el JAR incorrecto utilizando Java 5 o 6 recibirá un error (aunque no estoy seguro).

También intenté ejecutar el JAR explotado . Descomprimí todo el JAR en un directorio y lo ejecuté de esta manera.

java -cp <dir/ com.mycompany.test.Start

Trabajado como un encanto.

Línea de fondo. No use en exceso el maven-shade-plugin .

Tengo un proyecto en el trabajo donde construyo mi proyecto de esta manera.

  • Copio las dependencias de mi proyecto usando maven-dependency-plugin . Verifique el objetivo de copy-dependencies . Esto copia tus dependencias en target/dependency si recuerdo correctamente.
  • Utilizando maven-jar-plugin , agrego estas dependencias a mi MANAR.MF de JAR final como entradas de Class-Path usando estas opciones en la configuración de los complementos.

    <classpathPrefix>dependency/</classpathPrefix> <addClasspath>true</addClasspath>

    Así que tendré entradas de Class-Path como dependency/<artifactId>-<version>.jar , etc.

  • Después de esto, estoy usando maven-assembly-plugin para crear un ZIP de distribución que contenga mi JAR final y toda la dependency/ carpeta.
  • Cuando implemente mi aplicación, puedo ejecutarla como java -jar final.jar .

Principalmente he optado por usar esta solución, porque en mi proyecto uso algunos JAR de Bouncy Castle que los JAR tienen algo de extravagante esto y aquello dentro de su directorio META-INF . Cuando usé el maven-shade-plugin para crear mi JAR ejecutable final, todo el infierno se desató y me volví desagradable porque no se pudo encontrar el método y esta firma no tiene los errores correctos .

Deberías estar haciendo algo como esto también. Este negocio de sombreados Maven es demasiado oscuro para ser útil (juego de palabras).

Aquí hay una publicación de blog sobre todo el proceso que he tratado de describir justo arriba (gracias a baba ), tal vez ayude a alguien en el futuro.


mvn dependency:tree con su configuración y dará una diferencia cuando mueva el org.apache.poi más arriba en las declaraciones de dependencia.

Esto se toma de la Introducción al Mecanismo de Dependencia con respecto al orden de dependencia:

Mediación de dependencia : esto determina qué versión de una dependencia se usará cuando se encuentren varias versiones de un artefacto. Actualmente, Maven 2.0 solo admite el uso de la "definición más cercana", lo que significa que utilizará la versión de la dependencia más cercana a su proyecto en el árbol de dependencias. Siempre puede garantizar una versión al declararla explícitamente en el POM de su proyecto. Tenga en cuenta que si dos versiones de dependencia tienen la misma profundidad en el árbol de dependencias, hasta Maven 2.0.8 no se definió cuál ganaría, pero desde Maven 2.0.9 es el orden en la declaración lo que cuenta: la primera declaración gana .

Parece que hay un conflicto en su resolución de dependencia y que está causando su archivo jar corrupto (no sé por qué se corrompe).

De todos modos, aquí están las diferencias entre los dos poms (a la izquierda es el origen, a la derecha está con org.apache.poi más arriba):

( Tal vez es difícil ver en las imágenes, pero si amplías verás ) .

La gran diferencia es que en el pom no funcional los org.apache.httpcomponents:httpcore:jar:4.2.1 tienen una dependencia en commons-codec:commons-codec:jar:1.6 , y en el pom de trabajo esa dependencia ha sido anulado con commons-codec:commons-codec:jar:1.5 .

Supongo que hay un problema con la versión 1.6 de commons-codec junto con org.apache.poi:poi:jar:3.8 que necesita la versión 1.5 .

Editar

Después de esta excelente respuesta que explica por qué el archivo jar está dañado (demasiadas entradas en el contenedor) solo quiero agregar una solución simple que al menos funcione para su problema en particular.

Agregue la etiqueta <minimizeJar>true</minimizeJar> a su configuración maven-shade-plugin .

Después de eso, su línea de comando java -jar target/com.mycompany.test-1.0.0-SNAPSHOT.jar funcionará.