¿Cómo puedo crear un JAR ejecutable con dependencias usando Maven?

2398

Quiero empaquetar mi proyecto en un solo JAR ejecutable para su distribución.

¿Cómo puedo hacer que un proyecto de Maven empaquete todos los JAR de dependencia en mi JAR de salida?

soemirno
fuente
14
Explique a qué objetivo del complemento de dependencia se refiere. No conozco ningún objetivo que haga lo que pide la pregunta original: poner todas las dependencias, ya sea A) dentro del jar del autor a través del reempaquetado, o B) hacer un jar ejecutable que tenga a los demás en un classpath de MANIFEST.MF
Matthew McCullough
2
Puede encontrar esto útil racionaljava.com/2015/02/…
Dan

Respuestas:

2361
<build>
  <plugins>
    <plugin>
      <artifactId>maven-assembly-plugin</artifactId>
      <configuration>
        <archive>
          <manifest>
            <mainClass>fully.qualified.MainClass</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </plugin>
  </plugins>
</build>

y lo ejecutas con

mvn clean compile assembly:single

El objetivo de compilación debe agregarse antes del ensamblaje: individual o de lo contrario, el código de su propio proyecto no está incluido.

Ver más detalles en los comentarios.


Comúnmente, este objetivo está vinculado a una fase de construcción para ejecutarse automáticamente. Esto garantiza que el JAR se construya al ejecutar mvn installo realizar una implementación / lanzamiento.

<plugin>
  <artifactId>maven-assembly-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <mainClass>fully.qualified.MainClass</mainClass>
      </manifest>
    </archive>
    <descriptorRefs>
      <descriptorRef>jar-with-dependencies</descriptorRef>
    </descriptorRefs>
  </configuration>
  <executions>
    <execution>
      <id>make-assembly</id> <!-- this is used for inheritance merges -->
      <phase>package</phase> <!-- bind to the packaging phase -->
      <goals>
        <goal>single</goal>
      </goals>
    </execution>
  </executions>
</plugin>
IAdapter
fuente
22
Gracias @IAdapter. Tenga en cuenta que siempre debe hacer una compilación de antemano porque solo colocará lo que esté en "target / classes" en el JAR. Esto asegurará que el JAR incluya cualquier cambio que haya realizado recientemente en el código fuente. Por lo tanto, usted debe hacer algo como: mvn clean compile assembly:single.
Michael
10
He editado la pregunta para incluir el enlace de fase. Eliminé el objetivo de ensamblaje en desuso, porque nadie necesita saberlo.
Duncan Jones
2
Veo que esto no agrega los frascos al uber jar, sino que simplemente agrega todos los archivos de clase al jar.
pitchblack408
170
Sugerencia: también puede agregar el elemento <appendAssemblyId>false</appendAssemblyId>en el configurationpara evitar el molesto sufijo "-jar-with-dependencies" en el nombre
maxivis
66
olvida compiley estás jodido.
prayagupd
350

Puede usar el complemento de dependencia para generar todas las dependencias en un directorio separado antes de la fase del paquete y luego incluirlo en la ruta de clase del manifiesto:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>copy-dependencies</id>
            <phase>prepare-package</phase>
            <goals>
                <goal>copy-dependencies</goal>
            </goals>
            <configuration>
                <outputDirectory>${project.build.directory}/lib</outputDirectory>
                <overWriteReleases>false</overWriteReleases>
                <overWriteSnapshots>false</overWriteSnapshots>
                <overWriteIfNewer>true</overWriteIfNewer>
            </configuration>
        </execution>
    </executions>
</plugin>
<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <configuration>
        <archive>
            <manifest>
                <addClasspath>true</addClasspath>
                <classpathPrefix>lib/</classpathPrefix>
                <mainClass>theMainClass</mainClass>
            </manifest>
        </archive>
    </configuration>
</plugin>

Alternativamente usar ${project.build.directory}/classes/lib como OutputDirectory para integrar todos los archivos jar en el jar principal, pero luego deberá agregar un código de carga de clase personalizado para cargar los jar.

André Aronsen
fuente
3
+1 excelente. La razón por la que voy con maven-dependency-plugin en lugar de maven-assembly-plugin es que también estoy usando buildnumber-maven-plugin, y de esta manera puedo almacenar el número de versión en el manifiesto de cada jar individualmente.
PapaFreud
17
Me gusta tu solución. Utilizo ${project.build.directory}/classes/libcomo outputDirectorypara tener un .jar principal con todas las dependencias dentro, pero: ¿cómo agregar un código de carga de clase personalizado para cargar estos tarros? Necesito hacer ejecución de obras como: java -jar main-jar-with-deps.jar. Es posible ?
marioosh
3
@ André Aronsen, utilicé esta solución para agregar las dependencias en una carpeta lib dentro del jar, pero siempre obtengo una excepción de clase no encontrada, ¿podría aconsejarme cómo solucionarlo?
Mahmoud Saleh
11
¡+1 para ti! Parece que el complemento de ensamblaje de maven 'jar-with-dependencies' realmente no funciona bien. Me faltaban algunas entradas de META-INF / spring.schemas en el jar generado. Así que eliminé las dependencias jar-with-y utilicé su solución anterior. ¡¡¡Perfecto gracias!!!
Derek
99
Para cualquier otra persona que encuentre este problema, debe incluir la carpeta lib en el mismo directorio con su jar donde sea que transporte el jar.
Sparticles
224

Escribí en el blog sobre algunas formas diferentes de hacer esto.

Ver Jar ejecutable con Apache Maven (WordPress)

o ejecutable-jar-with-maven-example (GitHub)

Notas

Esos pros y contras son proporcionados por Stephan .


Para implementación manual

  • Pros
  • Contras
    • Las dependencias están fuera del frasco final.

Copiar dependencias a un directorio específico

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-dependency-plugin</artifactId>
  <executions>
    <execution>
      <id>copy-dependencies</id>
      <phase>prepare-package</phase>
      <goals>
        <goal>copy-dependencies</goal>
      </goals>
      <configuration>
        <outputDirectory>${project.build.directory}/${project.build.finalName}.lib</outputDirectory>
      </configuration>
    </execution>
  </executions>
</plugin>

Hacer que el frasco ejecutable y Classpath sean conscientes

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-jar-plugin</artifactId>
  <configuration>
    <archive>
      <manifest>
        <addClasspath>true</addClasspath>
        <classpathPrefix>${project.build.finalName}.lib/</classpathPrefix>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </manifest>
    </archive>
  </configuration>
</plugin>

En este punto, el jares realmente ejecutable con elementos de classpath externos.

$ java -jar target/${project.build.finalName}.jar

Hacer archivos desplegables

El jararchivo solo es ejecutable con el ...lib/directorio hermano . Necesitamos crear archivos para implementar con el directorio y su contenido.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-antrun-plugin</artifactId>
  <executions>
    <execution>
      <id>antrun-archive</id>
      <phase>package</phase>
      <goals>
        <goal>run</goal>
      </goals>
      <configuration>
        <target>
          <property name="final.name" value="${project.build.directory}/${project.build.finalName}"/>
          <property name="archive.includes" value="${project.build.finalName}.${project.packaging} ${project.build.finalName}.lib/*"/>
          <property name="tar.destfile" value="${final.name}.tar"/>
          <zip basedir="${project.build.directory}" destfile="${final.name}.zip" includes="${archive.includes}" />
          <tar basedir="${project.build.directory}" destfile="${tar.destfile}" includes="${archive.includes}" />
          <gzip src="${tar.destfile}" destfile="${tar.destfile}.gz" />
          <bzip2 src="${tar.destfile}" destfile="${tar.destfile}.bz2" />
        </target>
      </configuration>
    </execution>
  </executions>
</plugin>

Ahora tiene target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)cuál contiene el jary lib/*.


Complemento de ensamblaje de Apache Maven

  • Pros
  • Contras
    • No es compatible con la reubicación de clases (use el complemento maven-shade-plugin si se necesita la reubicación de clases).
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-assembly-plugin</artifactId>
  <executions>
    <execution>
      <phase>package</phase>
      <goals>
        <goal>single</goal>
      </goals>
      <configuration>
        <archive>
          <manifest>
            <mainClass>${fully.qualified.main.class}</mainClass>
          </manifest>
        </archive>
        <descriptorRefs>
          <descriptorRef>jar-with-dependencies</descriptorRef>
        </descriptorRefs>
      </configuration>
    </execution>
  </executions>
</plugin>

Usted tiene target/${project.bulid.finalName}-jar-with-dependencies.jar.


Complemento Apache Maven Shade

  • Pros
  • Contras
<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-shade-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>shade</goal>
      </goals>
      <configuration>
        <shadedArtifactAttached>true</shadedArtifactAttached>
        <transformers>
          <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
            <mainClass>${fully.qualified.main.class}</mainClass>
          </transformer>
        </transformers>
      </configuration>
    </execution>
  </executions>
</plugin>

Usted tiene target/${project.build.finalName}-shaded.jar.


onejar-maven-plugin

  • Pros
  • Contras
    • No se admite activamente desde 2012.
<plugin>
  <!--groupId>org.dstovall</groupId--> <!-- not available on the central -->
  <groupId>com.jolira</groupId>
  <artifactId>onejar-maven-plugin</artifactId>
  <executions>
    <execution>
      <configuration>
        <mainClass>${fully.qualified.main.class}</mainClass>
        <attachToBuild>true</attachToBuild>
        <!-- https://code.google.com/p/onejar-maven-plugin/issues/detail?id=8 -->
        <!--classifier>onejar</classifier-->
        <filename>${project.build.finalName}-onejar.${project.packaging}</filename>
      </configuration>
      <goals>
        <goal>one-jar</goal>
      </goals>
    </execution>
  </executions>
</plugin>

Plugin Spring Boot Maven

  • Pros
  • Contras
    • Agregue posibles clases innecesarias relacionadas con Spring y Spring Boot.
<plugin>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-maven-plugin</artifactId>
  <executions>
    <execution>
      <goals>
        <goal>repackage</goal>
      </goals>
      <configuration>
        <classifier>spring-boot</classifier>
        <mainClass>${fully.qualified.main.class}</mainClass>
      </configuration>
    </execution>
  </executions>
</plugin>

Usted tiene target/${project.bulid.finalName}-spring-boot.jar.

Jin Kwon
fuente
2
@caiohamamura Puede clonar el repositorio de GitHub y ver cómo funcionan todos los perfiles.
Jin Kwon
El problema estaba con el paquete que estaba usando: stackoverflow.com/a/12622037/2548351
caiohamamura
1
Creo que esta es probablemente la respuesta más completa a este tema.
Petr Bodnár el
139

Tomando la respuesta de Unnsresponded y reformateándola, tenemos:

<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
        </plugin>
    </plugins>
</build>

A continuación, recomendaría hacer de esto una parte natural de su compilación, en lugar de algo a lo que llamar explícitamente. Para hacer de esto una parte integral de su compilación, agregue este complemento a su pom.xmly vincúlelo al packageevento del ciclo de vida. Sin embargo, un problema es que debes llamar al assembly:singleobjetivo si lo pones en tu pom.xml, mientras que llamarías 'ensamblaje: ensamblaje' si lo ejecutas manualmente desde la línea de comandos.

<project>
  [...]
  <build>
      <plugins>
          <plugin>
              <artifactId>maven-assembly-plugin</artifactId>
              <configuration>
                  <archive>
                      <manifest>
                          <addClasspath>true</addClasspath>
                          <mainClass>fully.qualified.MainClass</mainClass>
                      </manifest>
                  </archive>
                  <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                  </descriptorRefs>
              </configuration>
              <executions>
                  <execution>
                      <id>make-my-jar-with-dependencies</id>
                      <phase>package</phase>
                      <goals>
                          <goal>single</goal>
                      </goals>
                  </execution>
              </executions>
          </plugin>
      [...]
      </plugins>
    [...]
  </build>
</project>
Matthew McCullough
fuente
10
El uso del enfoque en esta respuesta da como resultado el siguiente mensaje de error: 'No se pudo cargar el atributo de manifiesto de clase principal desde <archivo jar>', cuando se intenta ejecutar el JAR usando 'java -jar <archivo jar>'
Elmo
3
Se necesita archivar parte del complemento maven-jar-plugin <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> fully.qualified.MainClass </mainClass> </manifest> </archive>
Rade_303
44
Lo sentimos, esta respuesta es simplemente incorrecta, la etiqueta mainClass tiene que estar en la entrada del complemento de ensamblaje maven ya que está llamando durante el objetivo del paquete
Alex Lehmann
Me sorprende, ¿por qué pom.xml ya no tiene esto incluido después de mvn archetype: generate command? Es un poco molesto para manualmente copiar y pegar esto cada vez cuando se crea un nuevo proyecto Maven ...
wintermute
tipo de no tengo un método o clase principal, solo tengo clase con función. ¿Cómo puedo hacer un tarro y usarlo
Parlad
97

Use el complemento maven-shade-plugin para empaquetar todas las dependencias en un uber-jar. También se puede usar para construir un jar ejecutable especificando la clase principal. Después de intentar usar maven-assembly y maven-jar, descubrí que este complemento se adaptaba mejor a mis necesidades.

Encontré este complemento particularmente útil ya que combina el contenido de archivos específicos en lugar de sobrescribirlos. Esto es necesario cuando hay archivos de recursos que tienen el mismo nombre en los frascos y el complemento intenta empaquetar todos los archivos de recursos

Ver ejemplo a continuación

      <plugins>
    <!-- This plugin provides the capability to package the artifact in an uber-jar, including its dependencies and to shade - i.e. rename - the packages of some of the dependencies. -->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.4</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                    <configuration>
                        <artifactSet>
                        <!-- signed jars-->
                            <excludes>
                                <exclude>bouncycastle:bcprov-jdk15</exclude>
                            </excludes>
                        </artifactSet>

                         <transformers>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                                <!-- Main class -->
                                <mainClass>com.main.MyMainClass</mainClass>
                            </transformer>
                            <!-- Use resource transformers to prevent file overwrites -->
                            <transformer 
                                 implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>properties.properties</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>applicationContext.xml</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                                <resource>META-INF/cxf/cxf.extension</resource>
                            </transformer>
                            <transformer
                                implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
                                <resource>META-INF/cxf/bus-extensions.xml</resource>
                            </transformer>
                     </transformers>
                    </configuration>
                </execution>
            </executions>
        </plugin>

    </plugins>
Vijay Katam
fuente
Entonces, ¿cómo bcprov-jdk15.jar llega al classpath en tiempo de ejecución, dado que está excluido del proceso de sombreado?
Andrew Swan
Estaba siendo arrastrado por cxf-rt-ws-security, que es parte de mis dependencias
Vijay Katam
Nunca escuché sobre este complemento antes, pero resolvió mi problema con spring.handlers dentro de los frascos. ¡Gracias!
Alexandre L Telles
11
Aquellos que obtuvieron una excepción de seguridad, excluyen los DSA del Manifiesto. Consulte maven.apache.org/plugins/maven-shade-plugin/examples/…
ruhsuzbaykus
+1 He usado minijar: ueberjar en el pasado, pero el complemento minijar ahora está en desuso y reemplazado por
shadow
19

Durante mucho tiempo usé el complemento de ensamblaje maven , pero no pude encontrar una solución al problema "already added, skipping". Ahora, estoy usando otro complemento: onejar-maven-plugin . Ejemplo a continuación ( mvn packagebuild jar):

<plugin>
    <groupId>org.dstovall</groupId>
    <artifactId>onejar-maven-plugin</artifactId>
    <version>1.3.0</version>
    <executions>
        <execution>
            <configuration>
                <mainClass>com.company.MainClass</mainClass>
            </configuration>
            <goals>
                <goal>one-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Debe agregar el repositorio para ese complemento:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>
marioosh
fuente
¿Cómo deshacerse de los mensajes adicionales en la salida?
Alexandr
17

Puede usar maven-dependency-plugin, pero la pregunta era cómo crear un JAR ejecutable. Hacer eso requiere la siguiente alteración a la respuesta de Matthew Franglen (por cierto, usar el complemento de dependencia toma más tiempo para construir cuando se comienza desde un objetivo limpio):

<build>
    <plugins>
        <plugin>
            <artifactId>maven-jar-plugin</artifactId>
            <configuration>
                <archive>
                    <manifest>
                        <mainClass>fully.qualified.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
        <plugin>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>unpack-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>unpack-dependencies</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
    <resources>
        <resource>
            <directory>${basedir}/target/dependency</directory>
        </resource>
    </resources>
</build>

fuente
16

Puede usar el complemento maven-shade para construir un súper jar como se muestra a continuación

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-shade-plugin</artifactId>
    <executions>
        <execution>
            <phase>package</phase>
            <goals>
                <goal>shade</goal>
            </goals>
        </execution>
    </executions>
</plugin>
Minisha
fuente
Pero entonces, ¿cómo se desplegará esto en el repositorio?
Francesco Gualazzi
15

Otra opción si realmente desea volver a empaquetar los otros contenidos de JAR dentro de su JAR resultante único es el complemento Maven Assembly . Descomprime y luego vuelve a empaquetar todo en un directorio a través de <unpack>true</unpack>. Entonces tendrías un segundo pase que lo convirtió en un JAR masivo.

Otra opción es el complemento OneJar . Esto realiza las acciones de reempaquetado anteriores en un solo paso.

Matthew McCullough
fuente
14

Puede agregar lo siguiente a su pom.xml :

<build>
<defaultGoal>install</defaultGoal>
<plugins>
  <plugin>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>2.3.2</version>
    <configuration>
      <source>1.6</source>
      <target>1.6</target>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.3.1</version>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <artifactId>maven-assembly-plugin</artifactId>
    <configuration>
      <descriptorRefs>
        <descriptorRef>jar-with-dependencies</descriptorRef>
      </descriptorRefs>
      <archive>
        <manifest>
          <mainClass>com.mycompany.package.MainClass</mainClass>
        </manifest>
      </archive>
    </configuration>
    <executions>
      <execution>
        <id>make-my-jar-with-dependencies</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
      </execution>
    </executions>
  </plugin>
</plugins>
</build>

Luego, debe cambiar a través de la consola al directorio, donde se encuentra el pom.xml. Luego debe ejecutar mvn assembly: single y luego su archivo JAR ejecutable con dependencias se construirá con suerte. Puede verificarlo al cambiar al directorio de salida (destino) con cd ./target e iniciar su jar con un comando similar a java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

Probé esto con Apache Maven 3.0.3 .

Benny Neugebauer
fuente
13

Revisé cada una de estas respuestas buscando hacer un jar ejecutable que contenga todas las dependencias y ninguna funcionó correctamente. La respuesta es el complemento de sombra, es muy fácil y directo.

    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-shade-plugin</artifactId>
      <version>2.3</version>
      <executions>
         <!-- Run shade goal on package phase -->
        <execution>
        <phase>package</phase>
        <goals>
            <goal>shade</goal>
        </goals>
        <configuration>
          <transformers>
             <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                <mainClass>path.to.MainClass</mainClass>
             </transformer>
          </transformers>
        </configuration>
          </execution>
      </executions>
    </plugin>

Tenga en cuenta que sus dependencias deben tener un alcance de compilación o tiempo de ejecución para que esto funcione correctamente.

Este ejemplo vino de mkyong.com

dsutherland
fuente
Mientras arreglaba esto, ¿le importaría actualizar su reseña? No había tenido en cuenta sus pensamientos antes de publicar y rápidamente hice una solución al ver su comentario
dsutherland
2
El pluginelemento entra pom.xmldebajo build/plugins.
isapir
12

Podrías combinar el maven-shade-pluginy maven-jar-plugin.

  • El maven-shade-pluginpaquetes de sus clases y todas las dependencias en un solo archivo JAR.
  • Configure el maven-jar-pluginpara especificar la clase principal de su jar ejecutable (consulte Configurar el Classpath , capítulo "Hacer ejecutable el jar").

Ejemplo de configuración de POM para maven-jar-plugin:

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.3.2</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.example.MyMainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Finalmente cree el jar ejecutable invocando:

mvn clean package shade:shade
Oliver
fuente
3
El complemento Shade ahora tiene medios para especificar la entrada de clase principal en el manifiesto: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick
9

Ken Liu tiene razón en mi opinión. El complemento de dependencia de Maven le permite expandir todas las dependencias, que luego puede tratar como recursos. Esto le permite incluirlos en el artefacto principal . El uso del complemento de ensamblaje crea un artefacto secundario que puede ser difícil de modificar; en mi caso, quería agregar entradas de manifiesto personalizadas. Mi pom terminó como:

<project>
 ...
 <build>
  <plugins>
   <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
     <execution>
      <id>unpack-dependencies</id>
      <phase>package</phase>
      <goals>
       <goal>unpack-dependencies</goal>
      </goals>
     </execution>
    </executions>
   </plugin>
  </plugins>
  ...
  <resources>
   <resource>
    <directory>${basedir}/target/dependency</directory>
    <targetPath>/</targetPath>
   </resource>
  </resources>
 </build>
 ...
</project>
Matthew Franglen
fuente
1
¡Muy agradable! ¿No sería mejor utilizar la fase de generación de recursos para desempacar?
nawroth
9

Debería ser así:

<plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
        <execution>
            <id>unpack-dependencies</id>
            <phase>generate-resources</phase>
            <goals>
                <goal>unpack-dependencies</goal>
            </goals>
        </execution>
    </executions>
</plugin>

El desempaquetado debe estar en la fase de generación de recursos porque, si está en la fase de paquete, no se incluirá como recursos. Prueba el paquete limpio y lo verás.

kac-ani
fuente
7

¿Problema con la ubicación del archivo de ensamblaje compartido con maven-assembly-plugin-2.2.1?

Intente usar el parámetro de configuración descriptorId en lugar de los parámetros descriptors / descriptor o descriptorRefs / descriptorRef.

Ninguno de ellos hace lo que necesita: busque el archivo en classpath. Por supuesto, debe agregar el paquete donde reside el ensamblado compartido en el classpath de maven-assembly-plugin (ver a continuación). Si está utilizando Maven 2.x (no Maven 3.x), es posible que necesite agregar esta dependencia en pom.xml padre superior en la sección pluginManagement.

Vea esto para más detalles.

Clase: org.apache.maven.plugin.assembly.io.DefaultAssemblyReader

Ejemplo:

        <!-- Use the assembly plugin to create a zip file of all our dependencies. -->
        <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <configuration>
                        <descriptorId>assembly-zip-for-wid</descriptorId>
                    </configuration>
                </execution>
            </executions>
            <dependencies>
                <dependency>
                    <groupId>cz.ness.ct.ip.assemblies</groupId>
                    <artifactId>TEST_SharedAssemblyDescriptor</artifactId>
                    <version>1.0.0-SNAPSHOT</version>
                </dependency>
            </dependencies>
        </plugin>
Rostislav Stříbrný
fuente
7

Para resolver este problema, utilizaremos Maven Assembly Plugin que creará el JAR junto con sus JAR de dependencia en un solo archivo JAR ejecutable. Simplemente agregue la configuración del complemento a continuación en su archivo pom.xml.

<build>
   <pluginManagement>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <configuration>
               <archive>
                  <manifest>
                     <addClasspath>true</addClasspath>
                     <mainClass>com.your.package.MainClass</mainClass>
                  </manifest>
               </archive>
               <descriptorRefs>
                  <descriptorRef>jar-with-dependencies</descriptorRef>
               </descriptorRefs>
            </configuration>
            <executions>
               <execution>
                  <id>make-my-jar-with-dependencies</id>
                  <phase>package</phase>
                  <goals>
                     <goal>single</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
      </plugins>
   </pluginManagement>
</build>

Después de hacer esto, no olvide ejecutar la herramienta MAVEN con este comando mvn clean compile assembly: single

http://jkoder.com/maven-creating-a-jar-together-with-its-dependency-jars-into-a-single-executable-jar-file/

Anoop Rai
fuente
5

No responderé directamente a la pregunta ya que otros ya lo han hecho antes, pero realmente me pregunto si es una buena idea incrustar todas las dependencias en el propio jar del proyecto.

Veo el punto (facilidad de implementación / uso) pero depende del caso de uso de su proyecto (y puede haber alternativas (ver más abajo)).

Si lo usa completamente independiente, ¿por qué no?

Pero si usa su proyecto en otros contextos (como en una aplicación web, o se deja caer en una carpeta donde se encuentran otros frascos), es posible que tenga duplicados de jar en su classpath (los que están en la carpeta, el que está en los frascos). Tal vez no sea un acuerdo de oferta, pero generalmente evito esto.

Una buena alternativa

  • despliegue su aplicación como .zip / .war: el archivo contiene el jar de su proyecto y todos los jar dependientes;
  • use un mecanismo dinámico de carga de clases (vea Spring, o puede hacerlo fácilmente usted mismo) para tener un único punto de entrada de su proyecto (una sola clase para comenzar; vea el mecanismo de Manifiesto en otra respuesta), que se agregará (dinámicamente) a la classpath actual todos los otros frascos necesarios.

De esta manera, al final solo con un manifiesto y un "cargador principal de clases dinámico especial", puede comenzar su proyecto con:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
SRG
fuente
1
¿Cómo poner el frasco del proyecto y todos los frascos dependientes en un archivo entonces?
4

Para crear un JAR ejecutable desde la línea de comandos, simplemente ejecute el siguiente comando desde la ruta del proyecto:

mvn assembly:assembly
Mayank
fuente
3
Creo que aún necesita hacer algunas cosas en el pom.xmlcaso contrario Error reading assemblies: No assembly descriptors found.. Eso es lo que me pasa de todos modos.
Sridhar Sarnobat
3

Esta es la mejor manera que encontré:

  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <version>2.4</version>
    <configuration>
      <archive>
        <manifest>
        <addClasspath>true</addClasspath>
        <mainClass>com.myDomain.etc.MainClassName</mainClass>
        <classpathPrefix>dependency-jars/</classpathPrefix>
        </manifest>
      </archive>
    </configuration>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-dependency-plugin</artifactId>
    <version>2.5.1</version>
    <executions>
      <execution>
        <id>copy-dependencies</id>
        <phase>package</phase>
        <goals>
            <goal>copy-dependencies</goal>
        </goals>
        <configuration>
            <outputDirectory>
               ${project.build.directory}/dependency-jars/
            </outputDirectory>
        </configuration>
      </execution>
    </executions>
  </plugin>

Con esta configuración, todas las dependencias se ubicarán en /dependency-jars. Mi aplicación no tiene Mainclase, solo contextuales, pero una de mis dependencias tiene una Mainclase ( com.myDomain.etc.MainClassName) que inicia el servidor JMX y recibe startun stopparámetro o un parámetro. Entonces con esto pude iniciar mi aplicación así:

java -jar ./lib/TestApp-1.0-SNAPSHOT.jar start

Espero que sea útil para todos ustedes.

EliuX
fuente
3

Comparé los complementos de árbol mencionados en esta publicación. Genere 2 frascos y un directorio con todos los frascos. Comparé los resultados y definitivamente el complemento maven-shade-plugin es el mejor. Mi desafío era que tenía múltiples recursos de primavera que debían fusionarse, así como jax-rs y servicios JDBC. Todos se fusionaron correctamente con el complemento de sombra en comparación con el complemento de ensamblaje maven. En ese caso, el resorte fallará a menos que los copie en su propia carpeta de recursos y los fusione manualmente una vez. Ambos complementos generan el árbol de dependencia correcto. Tuve múltiples ámbitos como prueba, proporcionar, compilar, etc. La prueba y la provista fueron omitidas por ambos complementos. Ambos produjeron el mismo manifiesto, pero pude consolidar las licencias con el complemento de sombra utilizando su transformador. Con el complemento de dependencia de Maven, por supuesto, no lo haces No tengo esos problemas porque los frascos no se extraen. Pero, como algunos otros han señalado, debe llevar uno o más archivos adicionales para que funcione correctamente. Aquí hay un fragmento de pom.xml

            <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-dependency-plugin</artifactId>
            <executions>
                <execution>
                    <id>copy-dependencies</id>
                    <phase>prepare-package</phase>
                    <goals>
                        <goal>copy-dependencies</goal>
                    </goals>
                    <configuration>
                        <outputDirectory>${project.build.directory}/lib</outputDirectory>
                        <includeScope>compile</includeScope>
                        <excludeTransitive>true</excludeTransitive>
                        <overWriteReleases>false</overWriteReleases>
                        <overWriteSnapshots>false</overWriteSnapshots>
                        <overWriteIfNewer>true</overWriteIfNewer>
                    </configuration>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.6</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <mainClass>com.rbccm.itf.cdd.poller.landingzone.LandingZonePoller</mainClass>
                    </manifest>
                </archive>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-my-jar-with-dependencies</id>
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>2.4.3</version>
            <configuration>
                <shadedArtifactAttached>false</shadedArtifactAttached>
                <keepDependenciesWithProvidedScope>false</keepDependenciesWithProvidedScope>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/services/javax.ws.rs.ext.Providers</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
                        <resource>META-INF/spring.factories</resource>
                    </transformer>
                    <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.AppendingTransformer">
                        <resource>META-INF/spring.tooling</resource>
                    </transformer>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ServicesResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer"/>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ApacheLicenseResourceTransformer">
                    </transformer>
                </transformers>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
Fabio
fuente
2

Algo que me funcionó fue:

  <plugin>
    <artifactId>maven-dependency-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>prepare-package</phase>
        <goals>
          <goal>unpack-dependencies</goal>
        </goals>
        <configuration>
          <outputDirectory>${project.build.directory}/classes</outputDirectory>
        </configuration>
      </execution>

    </executions>
  </plugin>


  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-jar-plugin</artifactId>
    <executions>
      <execution>
        <id>unpack-dependencies</id>
        <phase>package</phase>
      </execution>
    </executions>
    <configuration>
      <archive>
        <manifest>
          <addClasspath>true</addClasspath>
          <classpathPrefix>lib/</classpathPrefix>
          <mainClass>SimpleKeyLogger</mainClass>
        </manifest>
      </archive>
    </configuration>
  </plugin>

Tuve un caso extraordinario porque mi dependencia era el sistema uno:

<dependency>
  ..
  <scope>system</scope>
  <systemPath>${project.basedir}/lib/myjar.jar</systemPath>
</dependency>

He cambiado el código proporcionado por @ user189057 con los cambios: 1) maven-dependency-plugin se ejecuta en la fase 2 "prepare-package") Estoy extrayendo las clases desempaquetadas directamente a "target / classes"

fascynacja
fuente
2

Intenté la respuesta más votada aquí, y pude obtener el jar ejecutable. Pero el programa no se ejecutó correctamente. No sé cuál fue la razón. Cuando trato de huir deEclipse , obtengo un resultado diferente pero cuando ejecuto el jar desde la línea de comandos obtengo un resultado diferente (se bloquea con un error de tiempo de ejecución específico del programa).

Tenía un requisito similar al OP solo porque tenía demasiadas dependencias (Maven) para mi proyecto. Afortunadamente, la única solución que funcionó para mí fue usarla Eclipse. Muy simple y muy directo. Esta no es una solución para el OP, pero es una solución para alguien que tiene un requisito similar pero con muchas dependencias de Maven,

1) Simplemente haga clic derecho en la carpeta de su proyecto (en Eclipse) y seleccione Export

2) Luego seleccione Java->Runnable Jar

3) Se le pedirá que elija la ubicación del archivo jar

4) Finalmente, seleccione la clase que tiene el método Principal que desea ejecutar y elija Package dependencies with the Jar filey haga clicFinish

Rocky Inde
fuente
2

Esto también podría ser una opción, podrás construir tu archivo jar

<build>
    <plugins>
        <plugin>
            <!-- Build an executable JAR -->
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-jar-plugin</artifactId>
            <version>2.4</version>
            <configuration>
                <archive>
                    <manifest>
                        <addClasspath>true</addClasspath>
                        <classpathPrefix>lib/</classpathPrefix>
                        <mainClass>WordListDriver</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>
    </plugins>
</build>
salmanbw
fuente
2

Para cualquiera que busque opciones para excluir dependencias específicas del uber-jar, esta es una solución que funcionó para mí:

<project...>
<dependencies>
        <dependency>
            <groupId>org.apache.spark</groupId>
            <artifactId>spark-core_2.11</artifactId>
            <version>1.6.1</version>
            <scope>provided</scope> <=============
        </dependency>
</dependencies>
<build>
        <plugins>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                    <archive>
                        <manifest>
                            <mainClass>...</mainClass>
                        </manifest>
                    </archive>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

Por lo tanto, no es una configuración de mvn-assembly-plugin sino una propiedad de la dependencia.

Paul Bormans
fuente
2

Ya hay millones de respuestas, quería agregar que no necesita <mainClass>si no necesita agregar entryPoint a su aplicación. Por ejemplo, las API pueden no tener necesariamente un mainmétodo.

configuración del complemento maven

  <build>
    <finalName>log-enrichment</finalName>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <configuration>
          <descriptorRefs>
            <descriptorRef>jar-with-dependencies</descriptorRef>
          </descriptorRefs>
        </configuration>
      </plugin>
    </plugins>
  </build>

construir

mvn clean compile assembly:single

verificar

ll target/
total 35100
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ./
drwxrwx--- 1 root vboxsf     4096 Sep 29 16:25 ../
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 archive-tmp/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 classes/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-sources/
drwxrwx--- 1 root vboxsf        0 Sep 29 16:25 generated-test-sources/
-rwxrwx--- 1 root vboxsf 35929841 Sep 29 16:10 log-enrichment-jar-with-dependencies.jar*
drwxrwx--- 1 root vboxsf        0 Sep 29 16:08 maven-status/
prayagupd
fuente
2

Añadir a pom.xml:

  <dependency>
            <groupId>com.jolira</groupId>
            <artifactId>onejar-maven-plugin</artifactId>
            <version>1.4.4</version>
  </dependency>

y

<plugin>
       <groupId>com.jolira</groupId>
       <artifactId>onejar-maven-plugin</artifactId>
       <version>1.4.4</version>
       <executions>
              <execution>
                     <goals>
                         <goal>one-jar</goal>
                     </goals>
              </execution>
       </executions>
</plugin>

Eso es. El siguiente paquete mvn también creará un tarro gordo adicionalmente, incluyendo todos los tarros de dependencia.

Aydin K.
fuente
1

El complemento de ensamblaje maven funcionó muy bien para mí. Pasé horas con el complemento de dependencia de maven y no pude hacerlo funcionar. La razón principal fue que tuve que definir en la sección de configuración explícitamente los elementos de artefactos que deberían incluirse tal como se describe en la documentación . Hay un ejemplo para los casos en que desea usarlo como: mvn dependency:copydonde no se incluyen ningún objeto de artefacto pero no funciona.

Chris
fuente
1

Esta publicación de blog muestra otro enfoque con la combinación de los complementos maven-jar y maven-assembly. Con la configuración de ensamblado xml de la publicación del blog, también se puede controlar si las dependencias se expandirán o solo se recopilarán en una carpeta y se hará referencia a ellas mediante una entrada de classpath en el manifiesto:

La solución ideal es incluir los archivos jar en una carpeta lib y el archivo manifest.mf del archivo jar principal incluye todos los archivos jar en classpath.

Y exactamente ese se describe aquí: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/

Jan Ziegler
fuente
0
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.4.1</version>
            <configuration>
                <!-- get all project dependencies -->
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
            </configuration>
            <executions>
                <execution>
                    <id>make-assembly</id>
                    <!-- bind to the packaging phase -->
                    <phase>package</phase>
                    <goals>
                        <goal>single</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
Shang Gao
fuente
1
Necesito un poco más de explicación de esto; ¿son esos comentarios solo documentación, o es necesario que haya opciones adicionales que se deben colocar en las ubicaciones de esos comentarios?
Mark Stewart,
-2

Bien, entonces esta es mi solución. Sé que no está usando el archivo pom.xml. Pero tuve el problema de que mi programa se compilara y ejecutara en Netbeans pero fallaba cuando probé Java -jar MyJarFile.jar. Ahora, no entiendo completamente a Maven y creo que por eso estaba teniendo problemas para que Netbeans 8.0.2 incluyera mi archivo jar en una biblioteca para ponerlos en un archivo jar. Estaba pensando en cómo solía usar archivos jar sin Maven en Eclipse.

Es Maven que puede compilar todas las dependencias y complementos. No Netbeans. (Si puede obtener Netbeans y poder usar java .jar para hacer esto, dígame cómo (^. ^) V)

[Resuelto - para Linux] abriendo una terminal.

Entonces

cd /MyRootDirectoryForMyProject

próximo

mvn org.apache.maven.plugins:maven-compiler-plugin:compile

próximo

mvn install

Esto creará un archivo jar en el directorio de destino.

MyJarFile-1.0-jar-with-dependencies.jar

Ahora

cd target

(Es posible que tenga que ejecutar: chmod +x MyJarFile-1.0-jar-with-dependencies.jar)

Y finalmente

java -jar MyJarFile-1.0-jar-with-dependencies.jar

Por favor mira

https://cwiki.apache.org/confluence/display/MAVEN/LifecyclePhaseNotFoundException

Publicaré esta solución en un par de otras páginas con un problema similar. Espero poder salvar a alguien de una semana de frustración.

mycowan
fuente
2
Intente abrir el proyecto Maven que creó con Netbeans. La regla básica de Netbeans es siempre crear un proyecto Maven y nunca una 'aplicación Java'. Agregar un complemento maven-shade como una de las respuestas. Funciona de maravilla.
rjdkolb