How do I copy dependencies to output directory with `maven package` - java

I have a project which uses LWJGL, and I would like to copy the required jars and related natives to the output directory of the generated jar. I would not like to inject the dependencies into the final jar itself.
I can run mvn package and mvn dependency:copy-dependencies, both of which work great.
My attempts to run the goal "copy-dependencies" is by adding an execution to the "maven-dependency-plugin" as follows:
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>
${project.build.directory}/libs
</outputDirectory>
</configuration>
</execution>
</executions>
and again, as referenced by this answer, with the same result: packaging completes, creating a jar, but no dependencies beside it. no logging that prepare-package is occurring, or the maven-dependency-plugin is being run at all.
I've also tried binding to other phases, such as package, validate, test, and none of them will cause an execution to occur. This is the only execution in my pom.xml. I have only a handful of plugins:
maven-clean-plugin
maven-resources-plugin
maven-compiler-plugin
maven-jar-plugin (with a config declaring its manifest, shown below)
maven-install-plugin
maven-dependency-plugin
Aforementioned config:
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>libs/</classpathPrefix>
<mainClass>
xyz.valnet.hadean.HadeanGame
</mainClass>
</manifest>
</archive>
</configuration>
I additionally have 3 profiles, for selecting which LWJGL natives to use by setting the property lwjgl-natives and that being used in the dependencies.
My question is mainly: what things could cause this execution to not occur.

plugins listed under <pluginManagement> will only get executed by projects in child directories which have their own pom.xml
plugins for execution in the current project should be listed without <pluginManagement>
to fix remove pluginManagement, or re-organize your plugins to correctly reflect which plugins should be run and which should be used for child projects.
<build>
<plugins>
[...]
</plugins>
<pluginManagement>
<plugins>
[...]
</plugins>
</pluginManagement>
</build>

Related

Maven copy-dependencies + shade - classpath management

To package a maven project with its dependencies, among many solutions, one may use maven-dependency-plugin with its goal copy-dependencies to get the dependencies in a folder besides, or one may use maven-shade-plugin to get all the code in a single jar.
I actually do both: I choose to have external dependencies (e.g. apache commons) as external libs, and my own dependencies (I have a multi-module maven parent project) shaded into a unique jar.
And it works, except for the classpath. I copy-dependencies with option excludeGroupIds to exclude my own maven group id. I shade with option to include only my own maven group id. Before that, I jar with option to add classpath to the manifest. All set, it works. But my classpath also contains my own dependencies that were actually shaded in the final jar.
It is no big deal, because the result works even with this erroneous classpath. But I wonder if there is a simple means to have the correct classpath, in order not to expose my internal structure to my users.
Here is a basic example demonstrating the problem:
<groupId>com.foo.bar</groupId>
<artifactId>com.foo.bar.launcher</artifactId>
<dependencies>
<dependency>
<groupId>com.foo.bar</groupId>
<artifactId>com.foo.bar.utils</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeGroupIds>com.foo.bar</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>com.foo.bar:*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
The resulting manifest contains this:
Class-Path: lib/com.foo.bar.utils-0.0.1.jar lib/commons-lang3-3.8.1.jar while the com.foo.bar.utils one does not exist.
If you look into the following mvnrepository link maven shade plugin depends upon maven dependency tree. As per the above pom.xml maven dependency plugin, you have excluded com.foo.bar dependency. You can omit the maven-dependency-plugin to create fat jar. It is not mandatory to use in case of shade plugin.
You can use the following command to check and copy all the dependencies used in the project.
mvn dependency:copy-dependencies
https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-shade-plugin/3.2.1

git commit id placed into POM memory doesn't go into manifest

I'm trying to coerce my Maven build to produce a line like this in the manifest of the resulting jar file:
SCM-Revision: fdf7abe874a0a54f580aec96da366c168446378c
such that the value is the git commit id.
So, I found this plugin, and I followed the instructions for setting it up. The verbose output and the ant run output looks fine, but the resulting manifest file just has the raw property reference, not the substituted string.
This is what I have in the parent pom for my multiproject build:
<plugin>
<groupId>pl.project13.maven</groupId>
<artifactId>git-commit-id-plugin</artifactId>
<version>2.2.3</version>
<executions>
<execution>
<id>get-the-git-infos</id>
<goals>
<goal>revision</goal>
</goals>
<phase>validate</phase>
</execution>
</executions>
<configuration>
<verbose>true</verbose>
<generateGitPropertiesFile>true</generateGitPropertiesFile>
<failOnNoGitDirectory>true</failOnNoGitDirectory>
<injectAllReactorProjects>true</injectAllReactorProjects>
<dotGitDirectory>${project.basedir}/../../.git</dotGitDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.0.2</version>
<configuration>
<archive>
<manifestEntries>
<SCM-Revision>${git.commit.id}, ${gitCommit}</SCM-Revision>
</manifestEntries>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<phase>package</phase>
<configuration>
<target>
<echo>Git-Infos: ${git.commit.id}, ${gitCommit}</echo>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
Because I was doing other experiments to get this to work, I also defined the following in an earlier "properties" section:
<gitCommit>${git.commit.id}</gitCommit>
When I run the build, I see this in the output, along with the verbose output from the plugin:
[INFO] --- maven-antrun-plugin:1.8:run (default) # usl-shared ---
[INFO] Executing tasks
main:
[echo] Git-Infos: fdf7abe874a0a54f580aec96da366c168446378c, fdf7abe874a0a54f580aec96da366c168446378c
[INFO] Executed tasks
However, this is what I get in the manifest file in the jar:
SCM-Revision: ${git.commit.id}, ${git.commit.id}
Somehow the property reference(s) in the jar plugin didn't substitute the property values.
Update:
I also note that the git.properties file was created in target/classes, but it's not in the jar file. This implies that the file was created after the jar file was created, which implies that those properties were set after the jar file was created, making this behavior understandable. This sounds like a problem with the "phase". I'm using the recommended configuration for this, but it sure seems like that would be the problem.
Update:
I don't know if this is relevant, but note that the packaging type of our artifact projects is "bundle", not "jar". We also use the maven-bundle-plugin. I tried as a test to change the packaging to "jar", and that made the property substitution work. It dropped all of our required osgi properties, however.
As you mentioned in your update, your problem is regarding maven-bundle-plugin.
So you can get rid of the maven-jar-plugin and maven-antrun-plugin if you don't use them for anything than for the commit id stuff.
Presuming your maven-bundle-plugin looks something like this:
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>${pom.groupId}.${pom.artifactId}</Bundle-SymbolicName>
<Bundle-Name>Service listener example</Bundle-Name>
<Bundle-Description>A bundle that displays messages at startup and when service events occur</Bundle-Description>
<Bundle-Vendor>Apache Felix</Bundle-Vendor>
<Bundle-Version>1.0.0</Bundle-Version>
<Bundle-Activator>tutorial.example1.Activator</Bundle-Activator>
<Import-Package>org.osgi.framework</Import-Package>
<SCM-Revision>${git.commit.id}, ${gitCommit}</SCM-Revision>
</instructions>
</configuration>
</plugin>
You can just add your attribute (i.e.SCM-Revision) in your maven-bundle-plugin your attribute as a Instruction in the <configuration> section.

Renaming a fat jar with Maven

When I create a jar file I want to fit inside my dependencies. For that, I use maven-assembly-plugin such as follows:
<build>
...
<plugins>
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<finalName>${project.artifactId}-GUI</finalName>
<archive>
<manifest>
<mainClass>gui.MyMainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<!-- <appendAssemblyId>false</appendAssemblyId>-->
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
This code works OK and it does what it's expected to do. However, this creates a new jar called myjar-GUI-jar-with-dependencies.jar. I would like to eliminate that "jar-with-dependencies" ending. Does anybody knows how to do that?
I have used that commented line you can see on my code, but that produces the following warning that I don't know how to solve it:
[WARNING] Configuration options: 'appendAssemblyId' is set to false, and 'classifier' is missing.
Instead of attaching the assembly file: [myJar-GUI].jar, it will become the file for main project artifact.
NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
[WARNING] Replacing pre-existing project main-artifact file: [myJar].jar with assembly file: [myJar-GUI].jar
EDITED
After the solution the user Tunaki suggested, I used a different pluggin and maven works as I want it to do it. The code is as follows:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<transformers>
<transformer
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<mainClass>gui.SparkISGUI</mainClass>
</transformer>
</transformers>
</configuration>
</plugin>
First, you need to understand why you are getting this warning.
The Maven convention is that one project should create a single main artifact. For a project of packaging jar, the main artifact is the result of the maven-jar-plugin. This plugin will package as a JAR the classes contained in your project only.
One project can eventually generate additional artifacts that will be distinguished from the main one by their classifier:
Beside the main artifact there can be additional files which are attached to the Maven project. Such attached filed can be recognized and accessed by their classifier.
The classifier is an identifier than will be appended to the main artifact name.
So what happens when you want to create an uber-jar? Somehow, your project needs to generate two jars. The main one will be a JAR containing the classes of your project and the second one will be the uber-jar resulting of maven-assembly-plugin. To distinguish this secondary additional artifact from the main one, the classifier jar-with-dependencies is added.
So when you remove the classifier, you effectively replace the main artifact with the uber-jar. maven-assembly-plugin will emit a warning in this case, and that's the warning you are having. You can ignore it completely: it just reminds you that you are replacing the main artifact of the project by an additional artifact.
Besides the maven-assembly-plugin, do note that you can also generate an uber-jar with the maven-shade-plugin:
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.

How to set additional Class-Path entries in manifest with onejar Maven plugin?

Is there a way to add an arbitrary classpath entry to a JAR file manifest using onejar-maven-plugin?
I found the way to configure maven-jar-plugin to do this, but it appears that there is no such option for onejar-maven-plugin.
This is not done to find additional classes (otherwise why use the onejar plugin, right?), but rather to locate a configuration file that must be external to the JAR.
Is there a direct solution or a workaround for this?
Is the usage of the one-jar plugin really required?
You can achieve the same goal (packaging in one single jar your application AND all the required dependencies, including transitive ones, AND add configuration for Class-Path AND using a more stable/standard plugin) applying the following approach:
Configure the Class-Path entry in your application Jar using the Maven Jar Plugin and the approach you mentioned in the question
Use the Maven Assembly Plugin to package one single JAR including dependencies, as explained here, in another stackoverflow question/answer.
An example of one-jar executable file (without using the one-jar plugin) could be as following:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<!-- your further configuration here -->
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.sample.MainApp</mainClass>
<!-- your further configuration here -->
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you need to further play with classpath and Maven, I would suggest to also check this question here on stackoverflow.
Adding arbitrary manifest entries is possible in 1.4.5:
<plugin>
<groupId>org.dstovall</groupId>
<artifactId>onejar-maven-plugin</artifactId>
<version>1.4.5</version>
<executions>
<execution>
<configuration>
<manifestEntries>
<Build-Status>Yes</Build-Status>
</manifestEntries>
</configuration>
<goals>
<goal>one-jar</goal>
</goals>
</execution>
</executions>
</plugin>
The onejar-maven-plugin project doesn't seem to be in active development anymore, so you might want to switch to other solutions (e.g. maven-assembly-plugin) eventually.
The plugin is not available on Maven Central. Someone else put up a version of it to Maven Central with a different group ID.
Additional libraries can be added to the classpath at the time of launch.
The property one-jar.class.path can be used
one-jar.class.path
Extra classpaths to be added to the execution environment. Use platform independent path separator '|'
Example: --one-jar.class.path="./lib/two.jar|/opt/lib/three.jar"
Source: http://one-jar.sourceforge.net/index.php?page=details

Why Maven Assembly Plugin does not include my project files in the jar with dependencies ?

I am using maven assembly plug in to package my project with all its dependency so i can run a simple java -jar myproject.jar and be able to run the project. However when I ran the jar it told me
Error: Could not find or load main class com.project.ServerStart
Then I unzipped the .jar file and found that the assembly does not include my project files, which is ridiculous !
When packaging the project I receive this warning
[WARNING] Cannot include project artifact: Amjar:amjar:pom:0.2; it doesn't have an associated file or directory.
This is my plugin config
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<finalName>amjar-${project.version}</finalName>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.project.ServerStart</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
What am I doing wrong ?
From the warning you've included in your question:
[WARNING] Cannot include project artifact: Amjar:amjar:pom:0.2; it doesn't have an associated
I'd guess that you've got the packaging in your pom.xml set to pom.
This is fine if your module is simply packaging a set of dependencies or resource files, however, if you also want Maven to create a jar containing the classes in you module you will need to set the packaging to jar.

Categories