Caminho de classe, incluindo JAR dentro de um JAR


134

É possível especificar um Java classpathque inclua um arquivo JAR contido em outro arquivo JAR?

Respostas:


94

Se você está tentando criar um único jar que contém seu aplicativo e suas bibliotecas necessárias, há duas maneiras (que eu conheço) de fazer isso. O primeiro é o One-Jar , que usa um carregador de classe especial para permitir o aninhamento de frascos. O segundo é o UberJar , (ou Shade ), que explode as bibliotecas incluídas e coloca todas as classes no jarro de nível superior.

Também devo mencionar que UberJar e Shade são plugins para Maven1 e Maven2, respectivamente. Como mencionado abaixo, você também pode usar o plug-in de montagem (que na realidade é muito mais poderoso, mas muito mais difícil de configurar corretamente).


81
Então aqui estamos, 5 anos depois. Parece que isso ainda é verdade. Muito triste :(
— T3rm1

3
A melhor maneira que conheço nos dias de hoje é usar o artefato de jar do IntelliJ. Extrai todas as classes dos frascos dependentes e as coloca em seu único frasco.
— enl8enmentnow

2
Isso não é possível em algumas situações, como quando seu usando implementações JCE como BouncyCastle que precisa ser assinado
— debuti

1
@ BrainSlugs83 ... O que você está tentando fazer? Acho que o carregador de classe e o empacotador do One-Jar ainda é a resposta para incluir um Jar em um projeto Jar (para Java SE). O uso do UberJar elimina o problema extraindo arquivos de classe no seu Jar.
— 9788 Steve Jobs Moyer

1
O link UberJar precisa de credenciais de login. Existe alguma página da web sucessora?
— Thomas Weller

50

Você NÃO deseja usar as soluções "explodir conteúdo JAR". Eles definitivamente tornam mais difícil ver as coisas (já que tudo é explodido no mesmo nível). Além disso, pode haver conflitos de nomenclatura (não deve acontecer se as pessoas usarem pacotes adequados, mas você nem sempre pode controlar isso).

O recurso que você deseja é um dos 25 principais RFEs da Sun : RFE 4648386 , que a Sun, em sua infinita sabedoria, designou como de baixa prioridade. Só podemos esperar que a Sun acorde ...

Enquanto isso, a melhor solução que eu encontrei (que eu gostaria que a Sun copiasse no JDK) é usar o carregador de classes personalizado JarClassLoader .


4
Na verdade, é quase garantido que os conflitos de nomes acontecem com coisas como a configuração do log4j e os textos de licença.
— Michael Borgwardt

1
Infelizmente, o JarClassLoader é GPLv3 / comercial, portanto provavelmente não será "copiado pelo sol (agora oracle)" e não poderá ser usado comercialmente, a menos que você tenha influência política interna e tempo para comprar algo. Concordo, no entanto, que os frascos que vomitam no diretório atual são uma coisa ruim.
— Gus

+1 para a idéia nesta resposta (embora eu não esteja marcando a resposta com +1): você não pode empacotar nenhum arquivo JAR assinado, portanto, essa técnica não pode ser usada em muitas situações (por exemplo, Java's activation.jar)
— Christopher Schultz

31

Após algumas pesquisas, encontrei um método que não requer o maven ou qualquer extensão / programa de terceiros.

Você pode usar "Caminho da classe" no seu arquivo de manifesto.

Por exemplo:

Criar arquivo de manifesto MANIFEST.MF

Manifest-Version: 1.0
Created-By: Bundle
Class-Path: ./custom_lib.jar
Main-Class: YourMainClass

Compile todas as suas aulas e execute jar cfm Testing.jar MANIFEST.MF *.class custom_lib.jar

csignifica criar archive findica que você deseja especificar o arquivo vé para entrada detalhada msignifica que passaremos o arquivo de manifesto personalizado

Certifique-se de incluir a lib no pacote jar. Você deve conseguir executar o jar da maneira normal.

com base em: http://www.ibm.com/developerworks/library/j-5things6/

todas as outras informações necessárias sobre o caminho da classe que você encontra aqui


19
Esta resposta não funciona. do documento do oracle (vinculado por banana acima): "O cabeçalho Class-Path aponta para classes ou arquivos JAR na rede local, não arquivos JAR no arquivo JAR"
— sebnukem

Qualquer coisa conhecida se isso também pode ser usado em uma configuração do Android.
— Mostowski Collapse

2
Ele funciona no cenário de jar executável (testado), mas pode não funcionar quando você deseja incluir um jar em um jar de biblioteca.
— Cychih

5
Oh não, não funciona, uma vez que eu me mudei custom_lib.jarpara longe, o frasco não pode ser executado mais :(
— Cychih

Como vários jarros especificados no caminho de classe?
— Abhishek Tiwari

22

Use a tag zipgroupfileset (usa os mesmos atributos de uma tag do conjunto de arquivos ); descompactará todos os arquivos no diretório e será adicionado ao seu novo arquivo. Mais informações: http://ant.apache.org/manual/Tasks/zip.html

Essa é uma maneira muito útil de contornar o problema do jar-in-a-jar - eu sei porque pesquisei essa questão exata do StackOverflow ao tentar descobrir o que fazer. Se você deseja empacotar um jar ou uma pasta de jars no seu jar com o Ant, esqueça todos esses caminhos de classe ou plug-ins de terceiros, tudo o que você precisa fazer é o seguinte (no Ant):

<jar destfile="your.jar" basedir="java/dir">
  ...
  <zipgroupfileset dir="dir/of/jars" />
</jar>

8

Se você estiver construindo com ant (estou usando ant do eclipse), basta adicionar os arquivos jar adicionais dizendo ao ant para adicioná-los ... Não é necessariamente o melhor método para manter um projeto mantido por várias pessoas, mas ele funciona para um projeto de uma pessoa e é fácil.

por exemplo, meu destino que estava criando o arquivo .jar era:

<jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
    <manifest>
        <attribute name="Author" value="ntg"/>
        ................................
        <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
    </manifest>
</jar>

Acabei de adicionar uma linha para torná-lo:

<jar ....">
    <zipgroupfileset dir="${external-lib-dir}" includes="*.jar"/>
    <manifest>
        ................................
    </manifest>
</jar>

Onde

<property name="external-lib-dir" 
          value="C:\...\eclipseWorkspace\Filter\external\...\lib" />

foi o dir com os frascos externos. E é isso...


6

Não sem escrever seu próprio carregador de classes. Você pode adicionar jars ao caminho de classe do jar, mas eles devem ser colocados juntos, não contidos no jar principal.


2

Você precisa criar um carregador de classes personalizado para fazer isso ou uma biblioteca de terceiros que suporte isso. Sua melhor aposta é extrair o jar do tempo de execução e adicioná-los ao caminho de classe (ou tê-los já adicionados ao caminho de classe).


2

Eu uso o maven para minhas compilações java, que tem um plugin chamado maven assembly plugin .

Ele faz o que você pede, mas como algumas das outras sugestões descrevem - basicamente explodindo todos os frascos dependentes e recombinando-os em um único frasco


A Maven assembly plug-in é bastante doloroso para uso ... UberJar e Sombra estão Maven1 e Maven2 plugins (um fato que eu deveria ter mencionado acima, e irá fazê-lo agora)
— Steve Moyer

2

Se você eclipsou o IDE, basta exportar seu JAR e escolher "Bibliotecas necessárias para o pacote no JAR gerado". O eclipse incluirá automaticamente os JARs dependentes necessários no JAR gerado, bem como gerou algum carregador de classes customizado do eclipse que carrega esses JARs automaticamente.


1

Eu estava prestes a aconselhar a extrair todos os arquivos no mesmo nível e, em seguida, criar um jarro com o resultado, pois o sistema de pacotes deve mantê-los bem separados. Essa seria a maneira manual, suponho que as ferramentas indicadas por Steve farão isso muito bem.



1

Bem, existe uma maneira muito fácil se você estiver usando o Eclipse.

Exporte seu projeto como um arquivo Jar "Executável" (clique com o botão direito do mouse na pasta do projeto no Eclipse, selecione "Exportar ..."). Ao definir as configurações de exportação, selecione "Extrair bibliotecas necessárias para o jar gerado". Lembre-se de selecionar "Extrair ..." e não "Empacotar bibliotecas necessárias ...".

Além disso : você deve selecionar uma configuração de execução nas suas configurações de exportação. Portanto, você sempre pode criar um main () vazio em alguma classe e usá-lo para sua configuração de execução.

De qualquer forma, não é garantido que funcione 100% do tempo - pois você verá uma mensagem pop-up solicitando que você verifique as licenças dos arquivos Jar incluídos e algo sobre não copiar arquivos de assinatura. No entanto, faço isso há anos e nunca encontrei um problema.


0

A extração para um Uber-dir funciona para mim, pois todos devemos usar root: \ java e ter código de saída em pacotes com controle de versão. Ou seja, ca.tecreations-1.0.0. A assinatura está correta porque os frascos estão intactos no local baixado. Assinaturas de terceiros intactas, extraídas para c: \ java. Aqui está o meu diretor de projeto. executar a partir do iniciador para java -cp c: \ java Launcher


Então, jarros em c: \ java \ jars. Origem, binários e recursos em c: \ java. Exclua backups, propriedades, keystore_private. Descompacte em c: \ java e execute com a ferramenta de formação de caminho de classe, talvez ca.tecreations.system.tools.SystemTool ou classe java comparável. Execute isso.
— Tim de Vries
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.