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:
- crear una nueva carpeta
- Copie el Pom.xml de arriba en la carpeta.
- Guarde el pequeño `public static void main (...). en src / main / java / com / mycompany / test / Start.java
- ejecutar
mvn clean package
- 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 decopy-dependencies
. Esto copia tus dependencias entarget/dependency
si recuerdo correctamente. Utilizando
maven-jar-plugin
, agrego estas dependencias a mi MANAR.MF de JAR final como entradas deClass-Path
usando estas opciones en la configuración de los complementos.<classpathPrefix>dependency/</classpathPrefix> <addClasspath>true</addClasspath>
Así que tendré entradas de
Class-Path
comodependency/<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 ladependency/
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á.