Maven - Create runnable jar and extract classes from dependent libraries - maven

Is there a maven plugin to create a runnable jar which extract all used classes from the dependent libraries?
The main reason I need this is the following: I developed a Java Web Start Application and if I creat the jar with shade plugin or jar plugin the JAR will be >13MB or the shade-plugin even forgets some classes which results in ClassNotFoundException.
With my old ant script the JAR is only 1,3MB small, it contains all required classes and it is downloaded and started really fast. But to go with technology I would like to switch to maven.
Thanks a lot!
My current pom:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<minimizeJar>true</minimizeJar>
<shadedClassifierName>min</shadedClassifierName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
What do I need to add for example the apache chemistry opencmis libraries (now the classes will be extracted but as I said some classes are still missing which opencmis uses itselfe)?

Please have a look at this question and the suggested workaround - referencing the needed classes to avoid the exclusion by the minimizeJar option.

Related

Maven shade plugin how to add package level resources

I am using shade plugin to build a fat or uber jar . Please see my shade plugin pom snippet as below
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.4.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>*:*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
I have some resource file for XML and properties which are not in src/main/resources but lies along with java packages.
When I build the code with maven with mvn clean package it compiles and add all dependent jar file but all resources files that are at the package level say src/main/java/x/y/z/hibernate.hbm.xml doesnt get added into respective place of fat jar.
Could someone please let me know what extra I have to do in above maven snippet to add those resources
I tried adding . in the artifacts set it didn't work . Also using maven assembly plugin its not working. I also searched direct eclipse plugin which can help but no clue. please help

maven-generated uberjar doesn't contain dependency classes

I'm running maven 3.6.0 on ubuntu 18.04.
My application’s pom.xml includes this dependency; the associated "neptus" jar is in my local .m2/repository:
<dependencies>
<dependency>
<groupId>pt.lsts.neptus</groupId>
<artifactId>neptus</artifactId>
<version>x.x</version>
</dependency>
My application actually does reference classes from the “neptus” jar file, so I want to include those classes in my project’s uberjar. Therefore the pom.xml also includes this, adapted from http://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>junit:junit</artifact>
<includes>
<include>junit/framework/**</include>
<include>org/junit/**</include>
</includes>
<excludes>
<exclude>org/junit/runners/**</exclude>
</excludes>
</filter>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
Yet the uberjar generated by 'mvn clean package' doesn’t contain any class files from the neptus artifact, and so my app throws java.lang.NoClassDefFoundError for those missing classes.
What am I doing wrong?
Thanks!
The maven-shade-plugin is ignored by default if that plugin is enclosed within a pluginManagement block, as it is in my case (sorry, not shown in my original post). The shade plugin does get executed if I do this:
% mvn package shade:shade
as described in this thread.

Running maven-shade and dockerfile-maven in different phases

My app uses maven-shade-plugin to pack things into single fatjar and then I would like to build a docker image using dockerfile-maven-plugin, my problem is that I can set the pom file properly so it would work.
What happens is that the docker plugin runs before the jar file was created...
I've tried to force the jar creation on prepare-package and the docker image build on package but it didn't work as expected...
any ideas?
EDIT: added pom snippet
<build>
<plugins>
<plugin>
<groupId>com.spotify</groupId>
<artifactId>dockerfile-maven-plugin</artifactId>
<version>${dockerfile-maven.version}</version>
<configuration>
<repository>test-docker-image</repository>
<tag>${docker.tag}</tag>
<buildArgs>
<JAR_FILE>${project.artifactId}-${project.version}-fat.jar</JAR_FILE>
<CONFIGURATION_FILE>configuration.json</CONFIGURATION_FILE>
</buildArgs>
</configuration>
<executions>
<execution>
<goals>
<goal>build</goal>
<!-- <goal>push</goal> -->
</goals>
<phase>install</phase>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>${maven.shade.plugin.version}</version>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<phase>package</phase>
<configuration>
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Main-Class>io.vertx.core.Launcher</Main-Class>
<Main-Verticle>MyVerticle</Main-Verticle>
</manifestEntries>
</transformer>
</transformers>
<minimizeJar>false</minimizeJar>
<outputFile>${project.build.directory}/deploy/${project.artifactId}-${project.version}-fat.jar</outputFile>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
I had both of these same plugins listed in the same order you have (docker-maven-plugin before maven-shade-plugin) and was seeing the same issue. I discovered that Maven executes plugins in the same phase in the order that they are listed, so moving maven-shade-plugin to be first resolved the issue for me locally. (Older versions of Maven don't order plugins this way, so use the latest if possible.)
This doesn't explain why it is not working for you when you change them to use different phases, but I'd suggest at least trying it out that reordering. Also be sure that you are using the latest versions of related plugins, like maven-release-plugin.
I was still seeing the undesired behavior in my build environment after doing all of the above, due to the parent of my project containing an execution for docker-maven-plugin; the fact that I was customizing it and reordering it in my own project didn't help, although it is unclear why it worked locally. Maven build profiles can also have a similar impact on ordering. My solution there was to bind the docker-maven-plugin:build execution to the install phase.
The output of mvn help:effective-pom should let you see the exact listing of plugins, executions, and profiles so that you can see exactly what the ordering will be for your project. Note that profiles are executed bottom-to-top, which is the opposite of plugins!

Using maven-bundle-plugin with the maven-shade-plugin

I'm using the maven-shade-plugin to relocate some packages during the package phase of my build. I'm also using the maven-bundle-plugin to generate a manifest. The problem is the bundle plugin runs before the shade plugin (during the process-classes phase), and doesn't include any of my shaded packages in the generated manifest's exports.
How can I get these two plugins to play nice with each other, so that my relocated packages are treated like any other package by the bundle plugin?
--
By request, the Shade and bundle sections of my POM:
<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>
<filters>
<filter>
<artifact>cglib:cglib</artifact>
<includes>
<include>net/sf/cglib/core/**</include>
<include>net/sf/cglib/proxy/**</include>
</includes>
</filter>
</filters>
<relocations>
<relocation>
<pattern>net.sf.cglib</pattern>
<shadedPattern>org.modelmapper.internal.cglib</shadedPattern>
</relocation>
<relocation>
<pattern>org.objectweb.asm</pattern>
<shadedPattern>org.modelmapper.internal.asm</shadedPattern>
</relocation>
</relocations>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
<executions>
<execution>
<id>bundle-manifest</id>
<phase>process-classes</phase>
<goals>
<goal>manifest</goal>
</goals>
</execution>
</executions>
<configuration>
<instructions>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>
org.modelmapper,
org.modelmapper.builder,
org.modelmapper.config,
org.modelmapper.convention,
org.modelmapper.spi
</Export-Package>
<Private-Package>
org.modelmapper.internal.**
</Private-Package>
<Import-Package>
*
</Import-Package>
<Include-Resource>
{maven-resources},
{maven-dependencies}
</Include-Resource>
</instructions>
</configuration>
</plugin>
Taken from here
Another option is to dump maven bundle plugin altogether and use Maven Shade Plugin ManifestResourceTransformer to add the desired OSGI metadata to the manifest.
Take a look at xbean-asm-shaded/pom.xml for a example.
<transformers>
<transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
<manifestEntries>
<Bundle-SymbolicName>${project.artifactId}</Bundle-SymbolicName>
<Export-Package>
org.apache.xbean.asm;org.modelmapper.builder; ...
</Export-Package>
<Import-Package>*</Import-Package>
<Private-Package>org.modelmapper.internal ...</Private-Package>
</manifestEntries>
</transformer>
Solution is very simple. You still can use maven-bundle-plugin and maven-shade-plugin at the same time. You just need to remember about the order. If you use bundle packaging maven bundle plugin will get executed during package phase before maven-shade. But that's not so wrong.
Here is the deal.
Use Private-Package: pkg.name.before.shading
Make maven-shade-plugin with one <include>null:null</include> - this will prevent shade plugin from creating empty jar
use maven-shade-plugin relocations - from pkg.name.before.shading to other.pkg.
You may see this trick working in FasterXML jackson-module-paranamer
I assume that after the compile phase is done you want to:
relocate some classes with the shade plugin
create a manifest with the bundle plugin
pack it all up with the jar plugin
The problem is the bundle plugin runs before the shade plugin
The bundle plugin is binded to process-classes phase which comes before the package phase to which the shade plugin is bound.
I suggest that you bind the shade plugin to process-classes phase also. Change shade plugin configuration like this:
<phase>process-classes</phase>
Since the shade plugin definition comes before the bundle plugin definition in the pom file, the shade plugin will run before the bundle plugin during the process-classes phase.
There is a neat transformer implementing just this functionality from Hazelcast - HazelcastManifestTransformer (ver 3.9). What it does is thoughtfully merging the Import-Package and Export-Package attributes, enabling the user to exclude extend/reduce the default merged result.
How to use it in your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.1.0</version>
<dependencies>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-build-utils</artifactId>
<version>3.9</version>
</dependency>
</dependencies>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<transformers>
<transformer implementation="com.hazelcast.buildutils.HazelcastManifestTransformer">
<mainClass>...</mainClass>
<!-- the tag below is required due to a missing null-check it seems -->
<overrideInstructions></overrideInstructions>
</configuration>
</executions>
</plugin>
The override instructions (Export/Import-Package) are comma delimited package names, preceded with an exclamation mark whenever we want to exclude those specific ones from the list.
Hope this helps! I do realize that's an old question, but seems the Hazelcast's transformer isn't gaining much publicity.

Easiest way to merge several modules (jars) into single jar file in Maven 2

Using maven-shade-plugin you can actually merge all dependency jars into single jar file. However I just want to merge several jar files (not all), similary like include-only x, and y, exclude others.
Is there any easiest way to specify only jar file(s) to be included, than to specify all jar files to be excluded?
maven-shade-plugin supports both inclusion and exclusion in its parameter artifactSet - isn't that working as you require ?
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>${project.artifactId}-shaded</finalName>
<artifactSet>
<includes>
<include>net.sf.buildbox:*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
...

Resources