Maven dependency stripVersion creates wrong classpath - java

I am trying to compile a project with Maven (through Eclipse), while stripping versions from dependency JARs. I have the following in my pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<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>
<stripVersion>true</stripVersion>
</configuration>
</execution>
</executions>
</plugin>
And indeed, the JARs are copied into lib/ without the version numbers. Alas, I get ClassNotFound, because the MANIFEST.MF in the generated executable JAR contains a classpath referring to the files including the version numbers, which naturally are not there.
What am I doing wrong, and how do I fix it?
Edit: JAR is created with maven-jar-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>my.main.class</mainClass>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addDefaultSpecificationEntries>true</addDefaultSpecificationEntries>
</manifest>
</archive>
</configuration>
</plugin>
I am using Run as -> Maven Install (Eclipse with m2e plugin)

Change the maven-jar-plugin to create a custom classpath layout without the version
Example:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifest>
<classpathLayoutType>custom</classpathLayoutType>
<customClasspathLayout>lib/$${artifact.artifactId}.$${artifact.extension}</customClasspathLayout>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>

Related

How to append folder to each classpath entry using maven dependency and jar plugin?

I am trying to append folder before for all classpath entries in manifest file.
As you can see in pom file below, I am using jar plugin to add classpath entries to manifest.
With dependency plugin I am copying dependencies to ${project.build.directory}/${finalName}-lib folder.
I want to keep these dependencies in that folder and change classpath entries to match ${finalName}-lib folder path.
pom:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<finalName>${jarpluginoutput}</finalName>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>desktop.core.Main</mainClass>
</manifest>
</archive>
<excludes>
<exclude>log4j2-test.properties</exclude>
<exclude>**/.keep</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>compile</includeScope>
<outputDirectory>${project.build.directory}/${finalName}-lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
Solution is made by adding <classPathPrefix>.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<finalName>${jarpluginoutput}</finalName>
<archive>
<manifest>
<classpathPrefix>${finalName}-lib</classpathPrefix>
<addClasspath>true</addClasspath>
<mainClass>desktop.core.Main</mainClass>
</manifest>
</archive>
<excludes>
<exclude>log4j2-test.properties</exclude>
<exclude>**/.keep</exclude>
</excludes>
</configuration>
</plugin>

Multiple dependencies with hibernate.cfg.xml at root in shaded jar

I am trying to shade a jar with multiple dependencies implementing hibernate entities. A number of the dependencies have the hibernate.cfg.xml at the root of the jar so only an indeterminate hibernate.cfg.xml is added to the final jar. Playing around with the appending transformer but have had no luck so far.
Thanks in advance for any suggestions!
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>**/hibernate.cfg.xml</resource>
</transformer>
I kinda gave up - just too many dependencies to deal with, defeated :( I went with a standard jar and library dir.
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.2.0</version>
<executions>
<execution>
<id>copy-libs</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/libs</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.2.0</version>
<configuration>
<outputDirectory>${project.build.directory}/bin</outputDirectory>
<archive>
<manifest>
<addDefaultImplementationEntries>true</addDefaultImplementationEntries>
<addClasspath>true</addClasspath>
<useUniqueVersions>false</useUniqueVersions>
<mainClass>com.loader.App</mainClass>
<classpathPrefix>../libs/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>

How to make jar file independent?

Please, could you explain me why my jar file doesn't execute outside the target folder? And how can I do it independent? To copy/paste it to another directory.
When I execute my jar outside target folder, NoClassDefFound error is produced. It can't load jars from dependencies.
This is my pom.xml:
<properties>
<docx4j.version>3.3.0</docx4j.version>
</properties>
<build>
<plugins>
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.epam.executor.Main</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<!-- Build an executable JAR with runtime dependencies so that this program can be executed from command line using java -jar command -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>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>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.docx4j</groupId>
<artifactId>docx4j</artifactId>
<version>${docx4j.version}</version>
</dependency>
</dependencies>
I execute my jar via this command with 3 parameters:
java -jar DocumentTemplate-1.0.jar D:\Trash\xml1.xml D:\Trash\template.docx D:\Trash\results.docx
I think you need to create one jar which includes all its executable dependencies also. I have been you one-jar plugin for it. try below plugin .
<plugin>
<!-- Build an executable JAR -->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>com.kulhade.elasticsearch.Indexer</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.4</version>
<executions>
<execution>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
Copy Dependencies to a specific directory
<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>
Make the Jar Executable and Classpath Aware
<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>
At this point the jar is actually executable with external classpath elements.
$ java -jar target/${project.build.finalName}.jar

How to put all dependencies in separate folder for runnable jar?

I'm using mvn package to create a runnable jar with all dependencies packed inside, which runs fine.
But I'd prefer to have all external dependencies packed in a separate folder. What would I have to change therefore?
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>my.MainApp</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Use the maven-dependencies-plugin to specify an output directory for the copy-dependencies execution.
<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}/lib/</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
Update:
To let the jar know where to find the lib folder, you can specify this as a Class-Path value in the manifest using the maven-jar-plugin
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>foo.bar.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
Hope this helps.

Different MANIFEST.MF for default jar-file and tests.jar

I'm trying to create different MANIFEST.MF files for the jar-packaged artifacts and the test-jar-packaged. The maven-jar-plugin being used to add additional stuff into the MANIFEST.MF - that works perfectly so far. But if I'd like to chose different template file for the MANIFEST.MF for the testproject, Maven only uses the second referenced template for both artifacts...
How can I get Maven to use the PROD-MANIFEST.MF-template for the normal jar-packaging and the TEST-MANIFEST.MF-template for test-jar-packaging?
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>test-manifest-mf</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>foo/TEST-MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>default-manifest-mf</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>foo/PROD-MANIFEST.MF</manifestFile>
</archive>
</configuration>
</plugin>
Wrap each plugin configuration you have provided in a profile.
<profiles>
<profile>
<id>PROD</id>
<build>
<plugins>
// your PROD plugin configuration
</plugins>
</build>
</profile>
<profile>
<id>TEST</id>
<build>
<plugins>
// your TEST plugin configuration
</plugins>
</build>
</profile>
</profiles>
Then you invoke Maven with a profile
mvn package -P PROD
Hope that helps.
Try this:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>test-manifest-mf</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>foo/TEST-MANIFEST.MF</manifestFile>
</archive>
</configuration>
</execution>
<execution>
<id>default-manifest-mf</id>
<phase>package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
<manifestFile>foo/PROD-MANIFEST.MF</manifestFile>
</archive>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
This configuration is performing 2 different executions of the same plugin, each of which has its own archive configuration.
If there is a parent pom somewhere in your hierarchy that has the archive configured outside of an execution, like this:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
... other archive config ...
</archive>
</configuration>
</plugin>
then that configuration will be merged with what you have by default. If you don't want that to happen, add the combine.self attribute to the <archive> element like so:
<archive combine.self="override">
as described in the plugins section of the POM reference.

Categories

Resources