Como posso criar um JAR executável com dependências usando o Maven?

2397

Quero empacotar meu projeto em um único JAR executável para distribuição.

Como posso fazer um projeto do Maven empacotar todos os JARs de dependência no meu JAR de saída?

soemirno
fonte
14
Por favor, explique a qual objetivo do plug-in de dependência você está se referindo. Não conheço nenhum objetivo que faça o que a pergunta original solicita: colocar todas as dependências A) dentro do frasco dos autores via reembalagem, ou B) criar um frasco executável que tenha os outros em um caminho de classe do MANIFEST.MF
Matthew McCullough
2
Você pode achar isso útil: racionaljava.com/2015/02/…
Dan

Respostas:

2360
<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>

e você executa com

mvn clean compile assembly:single

O objetivo de compilação deve ser adicionado antes da montagem: único ou não, o código em seu próprio projeto não está incluído.

Veja mais detalhes nos comentários.


Geralmente, esse objetivo está vinculado a uma fase de construção para ser executada automaticamente. Isso garante que o JAR seja construído ao executar mvn installou executar uma implementação / liberação.

<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
fonte
22
Obrigado @IAdapter. Observe que você sempre deve fazer uma compilação antes da mão, porque ela colocará apenas o que estiver em "target / classes" no JAR. Isso garantirá que o JAR inclua as alterações feitas recentemente no código-fonte. Assim, você deve fazer algo como: mvn clean compile assembly:single.
315 Michael
10
Editei a pergunta para incluir a ligação de fase. Eu removi a meta de montagem descontinuada, porque ninguém precisa saber disso.
Duncan Jones
2
Vejo que isso não adiciona os frascos ao jar uber, mas apenas adiciona todos os arquivos de classe ao jar.
pitchblack408
170
Dica: você também pode adicionar o elemento <appendAssemblyId>false</appendAssemblyId>no configurationpara evitar o irritante sufixo "-jar-with-dependencies" no nome
maxivis 6/15/15
6
esqueça compilee você está ferrado.
prayagupd
350

Você pode usar o plug-in de dependência para gerar todas as dependências em um diretório separado antes da fase do pacote e incluir isso no caminho de classe do manifesto:

<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>

Como alternativa, use ${project.build.directory}/classes/libcomo OutputDirectory para integrar todos os arquivos jar no jar principal, mas você precisará adicionar um código de carregamento de classe personalizado para carregar os jars.

André Aronsen
fonte
3
+1 Excelente. O motivo pelo qual eu uso o maven-dependency-plugin em vez do maven-assembly-plugin é que também estou usando o buildnumber-maven-plugin, e dessa maneira posso armazenar o número da versão no manifesto de cada jar individualmente.
PapaFreud 15/09
17
Eu gosto da sua solução. Eu uso ${project.build.directory}/classes/libcomo outputDirectoryter um .jar principal com todas as dependências dentro, mas - Como adicionar código de carregamento de classe personalizado para carregar esses jars? Eu preciso fazer execução de obras como: java -jar main-jar-with-deps.jar. Isso é possível ?
marioosh
3
@ André Aronsen, usei esta solução para adicionar as dependências em uma pasta lib dentro do jar, mas sempre recebo exceção de classe não encontrada, você pode aconselhar como corrigir isso.
Mahmoud Saleh
11
+1 para você !! Parece que o plug-in de montagem maven 'jar-with-dependencies' realmente não funciona bem. Estava faltando algumas entradas do META-INF / spring.schemas no jar gerado. Então, retirei o jar-with-dependencies e usei sua solução acima. Perfeito obrigado !!!
Derek
9
Para qualquer outra pessoa que encontre esse problema, inclua a pasta lib no mesmo diretório do seu jar para onde quer que o transporte.
Sparticles
224

Eu escrevi sobre algumas maneiras diferentes de fazer isso.

Consulte Jar executável com Apache Maven (WordPress)

ou executável-jar-com-maven-exemplo (GitHub)

Notas

Esses prós e contras são fornecidos por Stephan .


Para implantação manual

  • Prós
  • Contras
    • As dependências estão fora do jarro final.

Copiar dependências para um diretório 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>

Tornar o jar executável e o caminho de classe consciente

<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>

Nesse ponto, ele jaré realmente executável com elementos externos do caminho de classe.

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

Criar arquivos implantáveis

O jararquivo é apenas executável com o ...lib/diretório irmão . Precisamos criar arquivos para implantar com o diretório e seu conteúdo.

<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>

Agora você tem target/${project.build.finalName}.(zip|tar|tar.bz2|tar.gz)qual contém o jare lib/*.


Plugin de Montagem do Apache Maven

  • Prós
  • Contras
    • Não há suporte para realocação de classe (use maven-shade-plugin se for necessário realocação de classe).
<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>

Você tem target/${project.bulid.finalName}-jar-with-dependencies.jar.


Apache Maven Shade Plugin

  • Prós
  • 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>

Você tem target/${project.build.finalName}-shaded.jar.


onejar-maven-plugin

  • Prós
  • Contras
    • Não há suporte ativo 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>

Spring Boot Maven Plugin

  • Prós
  • Contras
    • Adicione possíveis classes relacionadas a Spring e Spring Boot desnecessárias.
<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>

Você tem target/${project.bulid.finalName}-spring-boot.jar.

Jin Kwon
fonte
2
@caiohamamura Você pode clonar o repositório do GitHub e ver como todos os perfis funcionam.
Jin Kwon
O problema estava no pacote que eu estava usando: stackoverflow.com/a/12622037/2548351
caiohamamura
1
Penso que esta é provavelmente a resposta mais completa para este tópico.
Petr Bodnár 16/11/19
139

Tomando a resposta não respondida e reformatá-la, temos:

<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>

Em seguida, eu recomendaria tornar isso uma parte natural da sua compilação, em vez de algo para chamar explicitamente. Para tornar isso parte integrante de sua construção, inclua esse plug-in no seu pom.xmle vincule-o ao packageevento do ciclo de vida. No entanto, um problema é que você precisa chamar o assembly:singleobjetivo se colocar isso em seu pom.xml, enquanto chamaria 'assembly: assembly' se o executasse manualmente a partir da linha de comando.

<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
fonte
10
O uso da abordagem nesta resposta resulta na seguinte mensagem de erro: 'Falha ao carregar o atributo de manifesto da classe principal a partir de <jar file>', ao tentar executar o JAR usando 'java -jar <jar file>'
Elmo
3
É necessário arquivar parte do maven-jar-plugin <archive> <manifest> <addClasspath> true </addClasspath> <mainClass> Fully.qualified.MainClass </mainClass> </manifest> </archive>
Rade_303
4
Desculpe, esta resposta está errada simples, a tag MainClass tem que ser sobre a entrada-assembly-plugin Maven desde que você está chamando de que, durante a meta pacote
Alex Lehmann
Estou surpreso, por que o pom.xml já não inclui isso após o comando mvn archetype: generate? É uma espécie de irritante para manualmente copiar e colar isso toda vez quando eu criar um novo projeto maven ...
Wintermute
Eu meio que não tenho um método ou classe principal, apenas tenho classe com função. como posso fazer frasco e usou-o
parlad
97

Use o maven-shade-plugin para empacotar todas as dependências em um uber-jar. Também pode ser usado para criar um jar executável, especificando a classe principal. Depois de tentar usar o maven-assembly e o maven-jar, descobri que esse plugin era mais adequado às minhas necessidades.

Achei esse plugin particularmente útil, pois mescla o conteúdo de arquivos específicos em vez de substituí-los. Isso é necessário quando existem arquivos de recursos com o mesmo nome nos jars e o plug-in tenta empacotar todos os arquivos de recursos

Veja o exemplo abaixo

      <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
fonte
Então, como o bcprov-jdk15.jar entra no caminho de classe no tempo de execução, pois ele é excluído do processo de sombreamento?
Andrew Swan
Ele estava sendo puxado por cxf-rt-WS-Security, que faz parte das minhas dependências
Vijay Katam
Nunca ouvi falar desse plugin antes, mas resolveu meu problema com spring.handlers dentro dos jarros. Obrigado!
Alexandre L Telles
11
Aqueles que receberam exceção de segurança excluem os DSA do Manifesto. Verifique maven.apache.org/plugins/maven-shade-plugin/examples/...
ruhsuzbaykus
+1 Eu usei minijar: ueberjar no passado, mas o plug-in minijar agora está obsoleto e substituído por shadow
rds
19

Long usou o plug-in maven assembly , mas não consegui encontrar uma solução para o problema "already added, skipping". Agora, estou usando outro plugin - onejar-maven-plugin . Exemplo abaixo ( mvn packagejar de compilação):

<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>

Você precisa adicionar repositório para esse plug-in:

<pluginRepositories>
    <pluginRepository>
        <id>onejar-maven-plugin.googlecode.com</id>
        <url>http://onejar-maven-plugin.googlecode.com/svn/mavenrepo</url>
    </pluginRepository>
</pluginRepositories>
marioosh
fonte
como se livrar de mensagens extras na saída?
Alexandr
17

Você pode usar o maven-dependency-plugin, mas a questão era como criar um JAR executável. Para fazer isso, é necessária a seguinte alteração na resposta de Matthew Franglen (btw, o uso do plug-in de dependência leva mais tempo para compilar ao iniciar a partir de um destino limpo):

<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>

fonte
16

Você pode usar o plugin maven-shade para criar um uber jar como abaixo

<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
fonte
Mas então como isso será implantado para repo?
Francesco Gualazzi
15

Outra opção se você realmente deseja reembalar o conteúdo de outros JARs em seu JAR resultante único é o plug-in Maven Assembly . Descompacta e depois empacota tudo em um diretório via <unpack>true</unpack>. Então você teria um segundo passe que o incorporou em um JAR maciço.

Outra opção é o plugin OneJar . Isso executa as ações de reembalagem acima, tudo em uma única etapa.

Matthew McCullough
fonte
14

Você pode adicionar o seguinte ao seu 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>

Depois, você deve alternar através do console para o diretório em que o pom.xml está localizado. Então você deve executar o assembly mvn: single e, em seguida, seu arquivo JAR executável com dependências será compilado. Você pode verificá-lo ao alternar para o diretório de saída (destino) com cd ./target e iniciar seu jar com um comando semelhante ao java -jar mavenproject1-1.0-SNAPSHOT-jar-with-dependencies.jar .

Eu testei isso com o Apache Maven 3.0.3 .

Benny Neugebauer
fonte
13

Eu passei por todas essas respostas procurando criar um frasco executável gordo contendo todas as dependências e nenhuma delas funcionou corretamente. A resposta é o plugin de sombra, é muito fácil e direto.

    <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>

Esteja ciente de que suas dependências precisam ter um escopo de compilação ou tempo de execução para que isso funcione corretamente.

Este exemplo veio de mkyong.com

dsutherland
fonte
Como consertei isso, você se importaria de atualizar seu comentário. Eu não tinha tomado seus pensamentos em consideração antes de enviar mensagens e rapidamente fez uma correção ao ver o seu comentário
dsutherland
2
O pluginelemento entra pom.xmlembaixo build/plugins.
Isapir
12

Você pode combinar o maven-shade-plugine maven-jar-plugin.

  • Ele maven-shade-pluginagrupa suas classes e todas as dependências em um único arquivo jar.
  • Configure maven-jar-pluginpara especificar a classe principal do seu jar executável (consulte Configurar o caminho de classe , capítulo "Tornar o jar executável").

Exemplo de configuração do 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>

Por fim, crie o jar executável chamando:

mvn clean package shade:shade
Oliver
fonte
3
O plugin Shade agora tem meios de especificar a entrada da classe principal no manifesto: maven.apache.org/plugins/maven-shade-plugin/examples/…
Chadwick
9

Ken Liu está certo na minha opinião. O plug-in de dependência maven permite expandir todas as dependências, que podem ser tratadas como recursos. Isso permite que você os inclua no artefato principal . O uso do plug-in assembly cria um artefato secundário que pode ser difícil de modificar - no meu caso, eu queria adicionar entradas de manifesto personalizadas. Meu pom acabou 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
fonte
1
Muito bom! Não seria melhor usar a fase de gerar recursos para a descompactação?
Nawroth 8/08
9

Deveria ser assim:

<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>

A descompactação deve estar na fase de gerar recursos, pois, se estiver na fase de pacote, não será incluída como recurso. Tente pacote limpo e você verá.

kac-ani
fonte
7

Problema ao localizar o arquivo de montagem compartilhado com o maven-assembly-plugin-2.2.1?

Tente usar o parâmetro de configuração descriptorId em vez dos parâmetros descriptors / descriptor ou descriptorRefs / descriptorRef.

Nenhum deles faz o que você precisa: procure o arquivo no caminho de classe. É claro que você precisa adicionar o pacote no qual o assembly compartilhado reside no caminho de classe do maven-assembly-plugin (veja abaixo). Se você estiver usando o Maven 2.x (não o Maven 3.x), pode ser necessário adicionar essa dependência no pom.xml principal do pai na seção pluginManagement.

Veja isso para mais detalhes.

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

Exemplo:

        <!-- 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ý
fonte
7

Para resolver esse problema, usaremos o Maven Assembly Plugin que criará o JAR junto com seus JARs de dependência em um único arquivo JAR executável. Basta adicionar a configuração do plugin abaixo no seu arquivo 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>

Depois de fazer isso, não esqueça de executar a ferramenta MAVEN com 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
fonte
5

Não responderei diretamente à pergunta, já que outras pessoas já fizeram isso antes, mas realmente me pergunto se é uma boa idéia incorporar todas as dependências no próprio jarro do projeto.

Entendo o ponto (facilidade de implantação / uso), mas isso depende do caso de uso do seu projeto (e pode haver alternativas (veja abaixo)).

Se você o usar totalmente independente, por que não.

Mas se você usar seu projeto em outros contextos (como em um aplicativo da Web ou soltar em uma pasta onde estão os outros jarros), poderá haver duplicatas jar em seu caminho de classe (os que estão na pasta e os que estão nos jarros). Talvez não seja um negócio de lances, mas geralmente evito isso.

Uma boa alternativa:

  • implante seu aplicativo como .zip / .war: o arquivo contém o jar do seu projeto e todos os jars dependentes;
  • use um mecanismo dinâmico do carregador de classes (consulte Spring, ou você pode fazer isso facilmente) para ter um único ponto de entrada do seu projeto (uma única classe para iniciar - consulte o mecanismo Manifest em outra resposta), que será adicionado (dinamicamente) ao caminho de classe atual, todos os outros frascos necessários.

Assim, no final, apenas um manifesto e um "carregador de classe dinâmico especial principal", você pode iniciar seu projeto com:

java -jar ProjectMainJar.jar com.stackoverflow.projectName.MainDynamicClassLoaderClass
SRG
fonte
1
Como colocar o frasco do projeto e todos os frascos dependentes em um arquivo?
4

Para criar um JAR executável a partir da própria linha de comando, execute o comando abaixo no caminho do projeto:

mvn assembly:assembly
Mayank
fonte
3
Eu acho que você ainda precisa fazer algumas coisas do pom.xmlcontrário Error reading assemblies: No assembly descriptors found.. É o que acontece comigo de qualquer maneira.
Sridhar Sarnobat
3

Esta é a melhor maneira que encontrei:

  <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>

Com essa configuração, todas as dependências serão localizadas /dependency-jars. Meu aplicativo não possui Mainclasse, apenas contexto, mas uma de minhas dependências possui uma Mainclasse ( com.myDomain.etc.MainClassName) que inicia o servidor JMX e recebe um startou um stopparâmetro. Então, com isso, eu era capaz de iniciar meu aplicativo assim:

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

Espero que seja útil para todos vocês.

EliuX
fonte
3

Comparei os plugins de árvore mencionados neste post. Eu gerei 2 frascos e um diretório com todos os frascos. Comparei os resultados e, definitivamente, o maven-shade-plugin é o melhor. Meu desafio era ter vários recursos de primavera que precisavam ser mesclados, além de serviços jax-rs e JDBC. Todos foram mesclados corretamente pelo plugin de sombra em comparação com o maven-assembly-plugin. Nesse caso, a primavera falhará, a menos que você as copie para sua própria pasta de recursos e as mescle manualmente uma vez. Ambos os plugins produzem a árvore de dependência correta. Eu tinha vários escopos como teste, fornecimento, compilação, etc. o teste e o fornecimento foram ignorados pelos dois plugins. Ambos produziram o mesmo manifesto, mas consegui consolidar licenças com o plug-in de sombra usando o transformador. Com o maven-dependency-plugin, é claro que você não Não tenho esses problemas porque os frascos não são extraídos. Mas, como alguns outros apontaram, é necessário carregar um arquivo extra para funcionar corretamente. Aqui está um trecho do 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
fonte
2

Algo que funcionou para mim foi:

  <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>

Eu tive um caso extraordinário porque minha dependência era do sistema um:

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

Alterei o código fornecido pelo @ user189057 com as alterações: 1) o maven-dependency-plugin é executado na fase "prepare-package" 2) Estou extraindo a classe descompactada diretamente para "target / classes"

fascynacja
fonte
2

Tentei a resposta mais votada aqui e consegui que o jar fosse executável. Mas o programa não foi executado corretamente. Não sei qual foi o motivo. Quando tento executar Eclipse, obtenho um resultado diferente, mas quando executo o jar na linha de comando, obtenho um resultado diferente (ele trava com um erro de tempo de execução específico do programa).

Eu tinha um requisito semelhante ao OP, pois tinha muitas dependências (Maven) para o meu projeto. Felizmente, a única solução que funcionou para mim foi o uso Eclipse. Muito simples e muito direto. Esta não é uma solução para o OP, mas é uma solução para alguém que tem um requisito semelhante, mas com muitas dependências do Maven,

1) Clique com o botão direito do mouse na pasta do projeto (no Eclipse) e selecione Export

2) Depois selecione Java->Runnable Jar

3) Você será solicitado a escolher o local do arquivo jar

4) Por fim, selecione a classe que possui o método Main que você deseja executar, escolha Package dependencies with the Jar filee clique emFinish

Rocky Inde
fonte
2

Isso também pode ser uma opção. Você poderá criar seu arquivo 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
fonte
2

Para quem procura opções para excluir dependências específicas do uber-jar, esta é uma solução que funcionou para mim:

<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>

Portanto, não é uma configuração do mvn-assembly-plugin, mas uma propriedade da dependência.

Paul Bormans
fonte
2

Já existem milhões de respostas, gostaria de acrescentar que você não precisa <mainClass>se não precisa adicionar o entryPoint ao seu aplicativo. Por exemplo, as APIs podem não ter necessariamente um mainmétodo.

configuração do plugin 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
fonte
2

Adicione ao pom.xml:

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

e

<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>

É isso aí. O próximo pacote mvn também criará um frasco de gordura adicionalmente, incluindo todos os jars de dependência.

Aydin K.
fonte
1

O maven-assembly-plugin funcionou muito bem para mim. Passei horas com o maven-dependency-plugin e não consegui fazê-lo funcionar. O principal motivo foi o fato de eu ter que definir explicitamente na seção de configuração os itens de artefato que devem ser incluídos conforme descrito na documentação . Há um exemplo para os casos em que você deseja usá-lo como:, em mvn dependency:copyque não há itens de artefato incluídos, mas ele não funciona.

Chris
fonte
1

Esta postagem do blog mostra outra abordagem com a combinação dos plug-ins do maven-jar e do maven-assembly. Com o xml de configuração de montagem da postagem do blog, também pode ser controlado se as dependências serão expandidas ou apenas coletadas em uma pasta e referenciadas por uma entrada de caminho de classe no manifesto:

A solução ideal é incluir os jars em uma pasta lib e o arquivo manifest.mf do jar principal inclui todos os jars no caminho de classe.

E exatamente esse é descrito aqui: https://caffebig.wordpress.com/2013/04/05/executable-jar-file-with-dependent-jars-using-maven/

Jan Ziegler
fonte
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
fonte
1
Precisa de um pouco mais de explicação sobre isso; esses comentários são apenas documentação ou é necessário que sejam necessárias opções adicionais nos locais desses comentários?
Mark Stewart
-2

Ok, então esta é a minha solução. Eu sei que não está usando o arquivo pom.xml. Mas eu tive o problema de meu programa compilar e executar no Netbeans, mas falhou quando tentei o Java -jar MyJarFile.jar. Agora, eu não entendo completamente o Maven e acho que foi por isso que estava tendo problemas para que o Netbeans 8.0.2 incluísse meu arquivo jar em uma biblioteca para colocá-los em um arquivo jar. Eu estava pensando em como eu costumava usar arquivos jar sem Maven no Eclipse.

É o Maven que pode compilar todos os dependanices e plugins. Não Netbeans. (Se você pode obter o Netbeans e poder usar java .jar para fazer isso, diga-me como (^. ^) V)

[Resolvido - para Linux] abrindo um terminal.

Então

cd /MyRootDirectoryForMyProject

Próximo

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

Próximo

mvn install

Isso criará um arquivo jar no diretório de destino.

MyJarFile-1.0-jar-with-dependencies.jar

Agora

cd target

(Pode ser necessário executar chmod +x MyJarFile-1.0-jar-with-dependencies.jar:)

E finalmente

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

Por favor, veja

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

Vou postar esta solução em algumas outras páginas com um problema semelhante. Espero que eu possa salvar alguém de uma semana de frustração.

Mycowan
fonte
2
Tente abrir o projeto Maven que você criou com o Netbeans. A regra básica do Netbeans é sempre criar um projeto Maven e nunca um 'aplicativo Java'. Adicione um plugin maven-shade-plugin como uma das respostas. Funciona como um encanto.
Rjdkolb