Building Maven fat jar conditionally - java

I followed the example in Building a fat jar using maven and now I can run the following to build/test and install my jars.
mvn clean compile install
However, install now takes a lot longer because we are now building a fat jar. Is it possible to have two versions of install where one just builds jars without dependencies and the other does that and in addition builds the fat jar, like:
mvn clean compile install
mvn clean compile install-fatjar
I know install-fatjar is not a valid phase but just want to give an idea of what I'm trying to accomplish, i.e. a conditional install where the fat jar is built only when an option is provided.

Create a profile for the fat jar and configure the maven assembly plugin to create the fat jar in this profile.
For example use this profile:
<profiles>
<profile>
<id>fatjar</id>
<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>
</profile>
</profiles>
Then you can build it by activating the profile
mvn -P fatjar clean install
where fatjar is the profile id.
Multiple profiles can also be activated
mvn -P fatjar,release install

Normally we don't use the fat-jar (or, uber-jar) as the main artifact.
You can make use of Assembly or Shade plugin to create a variation of the artifact (with a different classifier) which is a uber-jar.
It is strongly recommended that you still keep your "normal" artifact as is. If you want the uber-jar only occasionally, put the use of assembly/shade plugin for "uber-jar" creation in a profile, and activate the profile whenever you want. However, this should still generate you an "extra" uber-jar instead of making your main artifact a uber-jar.

Related

Whats the difference between mvn assembly:single and mvn compile assembly:single

When I am calling mvn assembly:single, it creates a jar, but the jar does not runs and the error says Error: Could not find or load main class.. But, when I am running mvn compile assembly:single, the jar created this time, runs as expected.
So my doubt is, why mvn assembly:single created jar not running and giving that error, while the later command created jar is running just fine.
Minimalistic pom
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<mainClass>com.org.taptest.tests.TestTAP</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
The difference is that assembly:single is a plugin goal while compile is a lifecycle phase.
Maven lifecycles are abstract build phases. When you invoke compile Maven will execute all phases until compile (included). In each phase it will execute the plugins that are registered to that phase.
Plugin goals are specific tasks that you can plug in a phase. The task of the assembly plugin for example is to package a distributable archive. That is what you define when you add a plugin <execution> to a pom.
Predefined lifecycles are selected through the <packaging>. E.g. the jar packaging.
Thus when you invoke assembly:single you tell maven to package a distribution archive. If there is nothing build that can be packaged the archive might be empty.
If you tell maven compile assembly:single is executes all phases until compile. Thus the sources are compiled to bytecode. And then it packages the compiled classes.

Maven : Distributing maven jar

I have a sample.jar created from a Maven project with all the dependencies (fat jar using maven assembly plugin) it requires. I use this jar in a client's application by using mvn install:install-file and including the dependency in the client application's pom.xml. This works.
But is there a way such that I do not have to build the sample.jar as a fat jar?
Instead let the client application's pom resolve the dependencies required by sample.jar as well by reading the sample.jar's pom.xml, if all of the dependencies of sample.jar are available from Maven central repo?
UPDATE:
My maven assembly plugin.
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>myMainClass</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</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>
In your repository of choice (Central, a proprietary Artifactory etc.), you need to upload both the pom and the (thin) jar.
When you declare a dependency in the client project, Maven will automatically look for both. It will use the pom to determine the transitive dependencies and will compile against the jar.
There are a few things to note here.
You didn't specify how exactly you generate the fat jar but normally maven-assembly-plugin will create an additional file next to the thin (regular) jar file it creates. You can check if that is the case by looking at your project's target folder.
Unless otherwise configured, maven-assembly-plugin would also make any artifact it creates a project artifact. When you run mvn install all project artifacts will be installed in the local Maven repo. That means you probably already have both the thin and the fat jar in your local Maven repo.
Assuming the above statements hold true in your particular case and your client project has a standard dependency record (with no special types, qualifiers, ...) it is most likely that it already uses the thin jar. You can check if that is the case by running mvn dependency:tree in your client project.
Please check this answer. Worth adding that either generatePom or pomFile options in the mvn install command are crucial for Maven to be able to resolve transitive dependencies if you use the thin version of your jar. Alternatively, you may upload your thin jar into an artifactory, if possible, that should also do it.
Useful references:
Installing an artifact with a custom POM
Generating a generic POM

The maven dependencies are not added to the jar in eclipse

I'm coding a maven project with eclipse 2018.09 under java 11 and I've a problem with the maven jar creation. When I clean package the project, it delivers me a jar but no dependencies are added into and i sometimes have warning in eclipse like:
classpath entry junit(for example) will not be exported it may result a ClassNotFoundException.
Which is in fact what's happening when i launch my jar project.
Thanks.
it delivers me a jar but no dependencies are added into [it]
it is totally normal. By default, when Maven builds a jar, it does not add any dependencies in it, but only the .class and resources of your current project.
When you run your programm you want it to find your dependencies otherwise you will face ClassNotFoundException. So you must configure your classpath to reference the dependencies.
1- if you want to run you programm from your local computer with Maven, use the exec Maven plugin with the <java> goal defined in your pom like explained here: https://www.mojohaus.org/exec-maven-plugin/usage.html#Java_goal
alternatively you can run it from a launcher in your IDE. The IDE will build the classpath for you and the classpath will corectly contain your dependencies.
2- if you want to run from the command line on any computer, you have to copy all of you dependencies in one directory (using Maven's dependency plugin mvn dependency:copy) and run you jar like this:
java -cp myProgram.jar:dependencyDirectory/* com.blabla.MainClass
(beware the use of ';' or ':' and '/' or '\' depending on Linux/Windows)
3- as an alternative you can run your jar with java -jar myprogram.jar but only if it contains a correct MANIFEST.MF where the location of all the dependencies are hardcoded.
My advice is to target solution 1 or 2 first.
PS: you can also create "fat jars" or "uber jars" containing your dependencies but I would advise you do not target this solution at first.
You can simply add this to your pom.xml (under the < plugins > tag):
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>App</mainClass>
</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>
Remember to change the mainclass to your entrypoint (which class the static void main(string[args]) is).
Now when you run the command mvn clean install there will be a jar in the targets folder with name yourproject-version-SNAPSHOT-jar-with-dependencies.jar

creating jar file of maven projects with netbeans

I am using netbeans to work on a project. I am using svn, so that I can commit to newer versions and revert to an older version in case I mess up. Now I want to create a jar file of this project but the build tab in the project properties does not display the packaging option, it only displays one option and that is of 'compile'.
If I create a new project (Java Application) it does show the packaging option and then I can easily create a jar file, but this maven project that I am working on does not work like this.
Please suggest me a way to create jar file out of my maven project.
Thanks,
Based on #yatskevich answer, you could go to your NetBeans Project Properties > Actions and add package to the Execute Goals of the following Actions:
Build project
Clean and Build project
Build with dependencies
Plus any other you feel should also package
I did this on NetBeans 7.2.1
PS: this will create the JAR on every change you make, so choose wisely where to add package. I don't mind it building a JAR for small projects on every build.
Open cmd (if you are on Windows) or any shell (if you are on Linux)
Navigate to your project directory (use cd command)
Run mvn clean package there.
Your jar will be in <project dir>/target.
Include maven-assembly-plugin plugin in your .pom file. It will instruct Maven to assemble your application with all it's dependencies.
Later when you will build your Netbeans project you will see your newly builded jar with all it's dependencies.
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.my.class</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Check out to learn more about creating Jar file with Maven: https://javatutorial.net/create-java-jar-file-with-maven

Running jar, setting classpath

I've got a project I've made with Maven. I compile a JAR, with "mvn package", and now I want to run it, preferably without setting some insane classpath, as it depends on Spring and half the internet or something. Is there any way I can run it easily? Something like "mvn run" would be great, or an option to throw in all dependencies into the jar so I can do "java -jar" would also be splendid.
How do you deal with this, and what do you recommend doing? Because exporting a CLASSPATH based on ~/.m2 would probably just be hurtful ;-)
Setting CLASSPATH and calling java -jar myjar.jar wouldn't work anyway. Because the java -jar command ignores the CLASSPATH environment variable as well as the -cp flag.
In this case you had to add the classpath entries to the jar's MANIFEST at the Class-Path key, like:
Class-Path: jar1-name jar2-name directory-name/jar3-name
Use the Maven Assembly Plugin - it will automatically build your JAR with all included dependencies, and you can set the main class parameter to make the JAR executable.
The documentation can be confusing, so here is an example of what your POM will look like:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.1</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>package.of.my.MainClass</mainClass>
<packageName>package.of.my</packageName>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
And then you can run as:
mvn assembly:assembly
You will want to look into the Maven Assembly Plugin. And then once you have created the XML file required by the plugin and have modified your POM file to work with the plugin, you can run it with:
mvn assembly:assembly
This will create the JAR with all of its dependencies.

Categories