Comment mettre tous les fichiers JAR requis dans un dossier de bibliothèque dans le fichier JAR final avec Maven?

105

J'utilise Maven dans mon application autonome et je souhaite empaqueter toutes les dépendances de mon fichier JAR dans un dossier de bibliothèque, comme mentionné dans l'une des réponses ici:

Comment puis-je créer un JAR exécutable avec des dépendances à l'aide de Maven?

Je veux que mon fichier JAR final ait un dossier de bibliothèque qui contient les dépendances en tant que fichiers JAR, pas comme ce maven-shade-pluginqui place les dépendances sous la forme de dossiers comme la hiérarchie Maven dans le dossier .m2.

Eh bien, en fait, la configuration actuelle fait ce que je veux, mais j'ai un problème avec le chargement des fichiers JAR lors de l'exécution de l'application. Je ne peux pas charger les classes.

Voici ma configuration:

<plugins>

    <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}/classes/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>com.myapp.MainClass</mainClass>
                </manifest>
            </archive>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <configuration>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-dependency-plugin</artifactId>
        <executions>
            <execution>
                <id>install</id>
                <phase>install</phase>
                <goals>
                    <goal>sources</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-resources-plugin</artifactId>
        <version>2.5</version>
        <configuration>
            <encoding>UTF-8</encoding>
        </configuration>
    </plugin>

</plugins>

Le projet fonctionne correctement à partir d'Eclipse et les fichiers JAR sont placés dans le dossier de la bibliothèque à l'intérieur de mon fichier JAR final comme je le souhaite, mais lors de l'exécution du fichier JAR final à partir du dossier cible, j'obtiens toujours ClassNotFoundException:

Exception in thread "main" java.lang.NoClassDefFoundError: org/springframework/context/ApplicationContext
Caused by: java.lang.ClassNotFoundException: org.springframework.context.ApplicationContext
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.security.AccessController.doPrivileged(Native Method)
        at java.net.URLClassLoader.findClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
        at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
        at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: com.myapp.MainClass. Program will exit.

Comment puis-je corriger cette exception?

Mahmoud Saleh
la source
1
quelle commande utilisez-vous pour exécuter le fichier jar? vous préférerez probablement le plugin maven exec?
Andrey Borisov
Le message d'exception est-il obsolète par rapport au fichier POM? Il semble que la classe principale com.myapp.MainClasssoit recherchée, non com.tastycafe.MainClass.
Duncan Jones
@Duncan Jones, problème de copier-coller, j'ai édité la question
Mahmoud Saleh
3
Notez que si vous voulez des fichiers jar dans le fichier jar, les chargeurs de classe standard de Java ne peuvent pas les comprendre.
Thorbjørn Ravn Andersen
Comment faire pour placer les dépendances maven dans un dossier lib mais en dehors du JAR?
ed22

Réponses:

81

Voici ma solution. Testez-le si cela fonctionne pour vous:

<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}/classes/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>test.org.Cliente</mainClass> -->
            </manifest>
            <manifestEntries>
                <Class-Path>lib/</Class-Path>
            </manifestEntries>
        </archive>
    </configuration>
</plugin>

Le premier plugin place toutes les dépendances dans le dossier target / classes / lib, et le second inclut le dossier de la bibliothèque dans le fichier JAR final, et configure le Manifest.mffichier.

Mais ensuite, vous devrez ajouter un code de chargement de classe personnalisé pour charger les fichiers JAR.

Ou, pour éviter le chargement de classe personnalisé, vous pouvez utiliser "$ {project.build.directory} / lib, mais dans ce cas, vous n'avez pas de dépendances dans le fichier JAR final, ce qui va à l'encontre de l'objectif.

Cela fait deux ans que la question a été posée. Le problème des fichiers JAR imbriqués persiste néanmoins. J'espère que cela aide quelqu'un.

gmode
la source
1
Utilisation: mvn install, cd target, java -jar MyJarFile-1.0.jar
djb
qu'est-ce que je manque? Cela crée une entrée de chemin de classe manifeste contenant "lib /" et tous les fichiers jar uniques du dossier lib. Est-ce voulu? Pourquoi?
gapvision
2
Cela a fonctionné après avoir changé "$ {project.build.directory} / classes / lib" en $ {project.build.directory} / lib
Rajendra Thorat
1
Malheureusement, comprend les dépendances déclarées comme fournies.
Philippe Gioseffi
@Rajendra merci, qui a aidé: $ {project.build.directory} / lib
Mindaugas K.
31

Actualisé:

<build> 
  <plugins> 
    <plugin> 
    <artifactId>maven-dependency-plugin</artifactId> 
    <executions> 
      <execution> 
        <phase>install</phase> 
          <goals> 
            <goal>copy-dependencies</goal> 
          </goals> 
          <configuration> 
             <outputDirectory>${project.build.directory}/lib</outputDirectory> 
          </configuration> 
        </execution> 
      </executions> 
    </plugin> 
  </plugins> 
</build> 
Ahmet Karakaya
la source
4
cela met le dossier lib en dehors du jar (ce qui n'est pas ce que je veux). est-ce mieux que de mettre la lib dans le bocal? et comment livrer l'application au client dans ce cas?
Mahmoud Saleh
c'est plus clair pour moi maintenant. laissez-moi faire une recherche sur google. Mais j'aimerais savoir pourquoi vous voulez copier tout le fichier jar de dépendance dans le dossier spécifié à l'intérieur du fichier jar exécutable. Si tous les fichiers jar de dépendance se trouvent dans le fichier jar, pourquoi avez-vous besoin de les localiser dans un dossier lib?
Ahmet Karakaya
23

Le moyen le plus simple et le plus efficace est d'utiliser un plugin uber comme celui-ci:

          <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <finalName>uber-${artifactId}-${version}</finalName>
            </configuration>
        </plugin>

Vous aurez tout normalisé dans un seul fichier JAR.

Andrey Borisov
la source
l'utiliser en plus de ma config actuelle? et que fait exactement ce plugin?
Mahmoud Saleh
15
Je ne veux pas que mon fichier jar ressemble à ceci, je veux avoir toutes les dépendances dans un dossier lib à l'intérieur du fichier jar comme le fait netbean.
Mahmoud Saleh
12

Le plugin exécutable packer maven peut être utilisé exactement dans ce but: créer des applications Java autonomes contenant toutes les dépendances sous forme de fichiers JAR dans un dossier spécifique.

Ajoutez simplement ce qui suit à votre pom.xmlintérieur de la <build><plugins>section (assurez-vous de remplacer la valeur de en mainClassconséquence):

<plugin>
    <groupId>de.ntcomputer</groupId>
    <artifactId>executable-packer-maven-plugin</artifactId>
    <version>1.0.1</version>
    <configuration>
        <mainClass>com.example.MyMainClass</mainClass>
    </configuration>
    <executions>
        <execution>
            <goals>
                <goal>pack-executable-jar</goal>
            </goals>
        </execution>
    </executions>
</plugin>

Le fichier JAR généré se trouve target/<YourProjectAndVersion>-pkg.jaraprès l'exécution mvn package. Toutes ses dépendances de compilation et d'exécution seront incluses dans le lib/dossier à l'intérieur du fichier JAR.

Avertissement: je suis l'auteur du plugin.

Cybran
la source
Je l'ai essayé et je peux dire que ça marche ... Comme vous l'avez dit, ce plugin crée un fichier jar, avec ses bibliothèques (jars) dans un répertoire lib dans le jar ... La configuration est vraiment simple .. Je pense que c'est quoi l'auteur de cette question attend ... Je vais vous donner mon vote ... Le seul inconvénient que j'ai trouvé là-dessus (c'est la raison pour laquelle je n'ai pas pu l'utiliser), il y a un retard lorsque j'exécute mon jar et l'application est affichée (environ 20 secondes) probablement à cause du processus d'enregistrement des bibliothèques dans le chargeur de classe personnalisé ... Mais c'est une excellente approche et un excellent plugin ...
Adam M. Gamboa G.
3

Voici comment je procède:

    <plugin>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2</version>
            <configuration>
                <appendAssemblyId>false</appendAssemblyId>
                <descriptorRefs>
                    <descriptorRef>jar-with-dependencies</descriptorRef>
                </descriptorRefs>
                <archive>
                    <manifest>
                        <mainClass>com.project.MainClass</mainClass>
                    </manifest>
                </archive>
            </configuration>
        </plugin>

Et puis je viens de courir:

mvn assembly:assembly
Eduardo Andrade
la source
1
Notez que vous devez toujours faire une compilation avant la main, car il assemblymettra simplement tout ce qui se trouve dans "target / classes" dans le JAR. Cela garantira que le JAR inclut toutes les modifications que vous avez récemment apportées au code source. Donc, vous devez faire quelque chose comme: mvn clean compile assembly:assembly.
naXa
2

J'ai trouvé cette réponse à la question:

http://padcom13.blogspot.co.uk/2011/10/creating-standalone-applications-with.html

Non seulement vous obtenez les fichiers lib dépendants dans un dossier lib, mais vous obtenez également un directeur bin avec à la fois un exécutable unix et dos.

L'exécutable appelle finalement java avec un argument -cp qui répertorie également toutes vos bibliothèques dépendantes.

L'ensemble se trouve dans un dossier d'assemblage à l'intérieur du dossier cible. Épique.

============= Oui, je sais que c'est un vieux fil de discussion, mais il arrive toujours en tête des résultats de recherche, alors j'ai pensé que cela pourrait aider quelqu'un comme moi.

user4815755
la source
1

Il s'agit clairement d'un problème de chemin de classe. Tenez compte du fait que le chemin de classe doit changer un peu lorsque vous exécutez votre programme en dehors de l'EDI. Cela est dû au fait que l'EDI charge les autres JAR par rapport au dossier racine de votre projet, alors que dans le cas du JAR final, ce n'est généralement pas le cas.

Ce que j'aime faire dans ces situations, c'est créer le JAR manuellement. Cela me prend au plus 5 minutes et cela résout toujours le problème. Je ne vous suggère pas de faire cela. Trouver un moyen d'utiliser Maven, c'est son but.

Radu Murzea
la source
@SoboLAN La construction manuelle du JAR n'est pas une solution ici. L'intention est d'utiliser Maven, qui est l'exact opposé de "manuel"!
Duncan Jones
@DuncanJones Vous avez tout à fait raison. Je suggère qu'il utilise Maven pour le faire. Cependant, je n'en ai aucune expérience et je ne savais pas exactement quelle solution recommander. J'ai modifié ma réponse pour refléter cela.
Radu Murzea