Using Maven shade plugin in a multi module project - NullPointerException - maven

I have a scenario where-in I need to create an uber jar of a multi module maven project including all modules and their dependencies. I tried using maven shade plugin. but it seems to work only when I use it at the module level. If I add the plugin entry in parent pom then the build breaks (it tries to shade the parent pom)
[INFO] Replacing original artifact with shaded artifact.
[INFO] Replacing null with C:\Projects\foo.bar\target\foobar-0.0.1-SNAPSHOT-shaded.pom
[INFO] ------------------------------------------------------------------------
[ERROR] BUILD ERROR
[INFO] ------------------------------------------------------------------------
[INFO] Error creating shaded jar: null: NullPointerException -> [Help 1]
It does seem to make sense since the <packaging> for the parent maven project is pom.
But there should be some way to create an uber jar for a multi module project... Any ideas people???

You should not be using your parent project's POM file to attempt shading; you should be using a separate aggregator project for this. Parent maven projects are used for inheritance while aggregator projects are used to perform aggregate functions over a group of sub-projects; like shading their JARs together into a uber jar. This project would simply be a pom file at the root directory of your project (the same level as all the sub-modules' folders) which references the sub-projects and has the shade plugin configuration. Make sure the packaing specified for this pom is JAR.
Here is the documentation explaining POM relationships and difference between Aggregation and Inheritance.

Yes ! You can ! :-)
Shade has an implementation problem: it doen't know when is running over pom (not jar or web) project. Pom projects don't generate binary artifacts, then shade doesn't find files to merge, move, etc., throwing NPE.
To solve this problem, create a parent POM from your aggegate-Pom project. Inside it, put the shade definitions and configuration configuring to some profile (eg. alwaysActiveProfiles) and install/deploy it with command:
mvn deploy -P -alwaysActiveProfiles
This command will install this shaded parent without running shade plugin pom (-alwaysActiveProfiles option supress shade plugin execution) and after that, your maven dependent projects will work.
Your shaded parent pom could looks like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>xxxxxxxx</groupId>
<artifactId>web-pom</artifactId>
<name>web-pom</name>
<version>1.0.0-SNAPSHOT</version>
<packaging>pom</packaging>
<build>
<pluginManagement>
<plugins>
<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>
...
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</pluginManagement>
</build>
<dependencies>
...
</dependencies>
<profiles>
<profile>
<id>alwaysActiveProfiles</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Remember that your setting.xml must have alwaysActiveProfiles enabled by default, otherwise shade will not run in your dependences shade-pom projects.

I was having the same problem with version 1.6 of the plugin, I updated to 2.2 and the problem was solved

Related

Install über jar with maven-shaded-plugin

I have been using maven assembly plugin to create uber jar and deploy to Artifactory.
I switched to maven shade plugin to shade some dependencies.
Now my jar is not deployed during install phase.
In the maven assembly plugin documentation:
When the assembly is created it will use the assemblyId as the
artifact's classifier and will attach the created assembly to the
project so that it will be uploaded into the repository in the install
and deploy phase.
This is not a case for shaded plugin.
How to configure maven pom to deploy uber jar created with shaded plugin?
You have to tell maven-shade-plugin to attach the shaded artifact which can be done via:
<project>
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>jackofall</shadedClassifierName> <!-- Any name that makes sense -->
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
...
</project>
I also had this problem, where mvn install would build a shaded jar in my target directory but install the non-shaded one to my local Maven repository.
What ultimately proved to be the cause was that I had <finalName> defined in my maven-shade-plugin configuration. That ended up saving the shaded jar under that specific name, while the non-shaded jar took the default jar name which mvn install must look for when it comes time to install. Without <finalName> present, it copied the shaded jar appropriately into the local Maven repository.
With <shadedArtifactAttached>, I could get the shaded jar installed, but only suffixed with shadedClassifierName while the non-shaded jar was present under the normal artifact name, causing libraries dependent on it to pick up the non-shaded jar over the shaded one (which was not what I wanted in this case as I'm building a library with some dependencies shaded).

How to resolve parent pom dependency issue: Failed to read artifact descriptor; Could not find artifact?

I recently published three artifacts to Maven Central: https://search.maven.org/search?q=ced2ar3-rdb
The three are part of the same project and are published concurrently.
I'm now trying to build a new project using ced2ar-rdb and ced2ar-rdb-tests as dependencies, but not where in my code do I reference the parent pom file (ced2ar3-rdb-parent; I don't actually want to use it and didn't think I needed it). However, when I try to build my project that uses ced2ar-rdb as a dependency, I get this error:
[ERROR] Failed to execute goal on project ced2ar3-services-core: Could not resolve dependencies for project edu.cornell.
ncrn.ced2ar:ced2ar3-services-core:jar:0.0.0: Failed to collect dependencies at edu.cornell.ncrn.ced2ar:ced2ar3-rdb:jar:0
.0.1: Failed to read artifact descriptor for edu.cornell.ncrn.ced2ar:ced2ar3-rdb:jar:0.0.1: Could not find artifact edu.
cornell.ncrn.ced2ar:ced2ar3-rdb-parent:pom:${ced2ar.version} in central (https://repo.maven.apache.org/maven2) -> [Help
Is the issue related to the fact that I have <version>${ced2ar.version}</version> in the parent pom, even though ${ced2ar.version} appears correctly defined in <properties> further down in the file?
Is the issue related to the fact that I have
${ced2ar.version} in the parent pom, even though
${ced2ar.version} appears correctly defined in further
down in the file?
No, the problem comes from the way which you declared the child modules.
Here is an extract of the rdb module pom.
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>ced2ar3-rdb-parent</artifactId>
<groupId>edu.cornell.ncrn.ced2ar</groupId>
<version>${ced2ar.version}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>ced2ar3-rdb</artifactId>
</project>
The ${ced2ar.version} property defined in the parent version of the child project cannot be resolved without building the reactor project that first builds the parent pom that defines this property. That's why your build works in development (with the reactor) but doesn't work without it.
To solve your issue you could use the revision standard property with the flatten-maven-plugin that will help you to set a unique version between the parent and the child.
Your reactor pom could look like :
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>${revision}</version>
...
<properties>
<revision>1.0.0</revision>
</properties>
<modules>
<module>rdb</module>
<module>rdb-tests</module>
..
</modules>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
And the rdb pom.xml for example like that :
<project>
<parent>
<groupId>my-group</groupId>
<artifactId>my-parent</artifactId>
<version>${revision}</version>
</parent>
<artifactId>rdb</artifactId>
...
</project>
About your comment :
I get an invalid POM error with: "Project name missing, Project
description missing, Project URL missing, SCM URL missing, Developer
information missing". Indeed, after inspecting the generated
.flattened-pom.xml, I do not see these fields
it is expected as the flattened plugin strips some metadata of the original POM :
The flattened POM is a reduced version of the original POM with the
focus to contain only the important information for consuming it.
Therefore information that is only required for maintenance by
developers and to build the project artifact(s) are stripped. Starting
from here we specify how the flattened POM is created from the
original POM and its project
But you can override this default by adding the elements that you don't want to strip in the pomElements parameter of the plugin.
For example :
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>flatten-maven-plugin</artifactId>
<version>1.0.0</version>
<configuration>
<updatePomFile>true</updatePomFile>
<pomElements>
<name/>
<description/>
<developers/>
<contributors/>
<url/>
<scm/>
</pomElements>
</configuration>
<executions>
<execution>
<id>flatten</id>
<phase>process-resources</phase>
<goals>
<goal>flatten</goal>
</goals>
</execution>
<execution>
<id>flatten.clean</id>
<phase>clean</phase>
<goals>
<goal>clean</goal>
</goals>
</execution>
</executions>
</plugin>
This works well for child modules that are directly under the parent module, but I can't get mvn install to work for child modules that are more than 1 level deep when one of the child modules depends on another child module. For example, consider this hierarchy:
└── root (pom type)
└── child (pom type)
├── child-1 (jar type)
└── child-2 (jar type; depends on child-1)
With the configuration described in the maven docs, I can run mvn install successfully from all directories except child-2. In child-2, I get this error:
[ERROR] Failed to execute goal on project child-2: Could not resolve dependencies for project com.mygroup:child-2:maven-archetype:local: Failed to collect dependencies at com.mygroup:child-1:jar:local: Failed to read artifact descriptor for com.mygroup:child-1:jar:local: com.mygroup:root:pom:${revision} was not found in https://maven-central.storage-download.googleapis.com/maven2/ during a previous attempt. This failure was cached in the local repository and resolution is not reattempted until the update interval of central has elapsed or updates are forced -> [Help 1]

How to create additional jar file with contents of all modules during maven build?

I have a multi-module maven project (say project-xxx). Lets say it consists of 5 modules:
project-xxx (war)
--> module-1 (jar)
--> module-2 (jar)
--> module-3 (jar)
--> module-4 (jar)
--> module-5 (jar)
When the maven project is built, the war file is generated and it includes the jar files of the 5 modules as well.
Now, for a different purpose (i.e., deploy to a distributed cache, so we can run queries from command-line), I want to generate a single `jar' file as well which includes the java classes from all modules. I'm aware that it is against maven's philosophy to generate more than one artifact and I read this blog post and a few other questions on SO.
But creating this single jar file would greatly simplify a few other things in my project. What would be the best approach to go about generating this single jar file?
I am very much in favor of the one artifact per Maven project convention. That being said, if you need a single artifact that contains all of the classes for all of the modules, then make a dedicated single project to do so:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>your-group-id</groupId>
<artifactId>one-jar-to-rule-them-all</artifactId>
<version>your-version</version>
<dependencies>
<dependency>
<groupId>your-group-id</groupId>
<artifactId>module-1</artifactId>
<version>your-version</version>
</dependency>
.
.
.
<dependency>
<groupId>your-group-id</groupId>
<artifactId>module-5</artifactId>
<version>your-version</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.2</version>
<configuration>
<!--
This restricts the jar to classes from your group;
you may or may not want to do this.
-->
<artifactSet>
<includes>
<include>your-group-id</include>
</includes>
</artifactSet>
<createDependencyReducedPom>true</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
This example project depends on each module and then uses the maven-shade-plugin to combine all of those modules together into a single jar artifact. You could also make this a child module of your parent project-xxx so it gets built by the reactor. This way, you can have both a war and an uber jar, but still keep the modularity of a standard Maven build.
I think you should consider introducing first separate profiles, so that profile1 would contain the configuration to result a proper war packaging. Profile2 could contain configuration using the maven-shade-plugin, in order to create an UBER jar out of your existing modules. Profiles are a very clean and maven-ish way to split different concerns.
For maven profiles see here. For the maven-shade-plugin see here.
Hope that helps.

Maven: How to relase an artifact without any project specific settings like parent pom or scm?

i have the task to build an artifact of an application that should be shipped to a customer. The artifact is a client-jar that can be used to access an ejb-application on a server.
As it is build out of a multi-module project, the artifact's pom contains the reference to a parent pom and scm information that should not be shipped to the customer.
Is there a maven way to remove those information or, in case of the parent pom, to resolve the parent pom and include its data in the client-jar's pom directly.
The customers will not have access to our intern maven repository.
You can remove all information from META-INF, see:
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
</configuration>
</plugin>
</plugins>
And you can use maven assembly plugin (or shade) to build jar file with all dependencies.

How to build maven project without version?

I have a maven project that I want to build without version.
Now, when I build the project using maven, it creates this commonjerseylib-1.0.war but I need this commonjerseylib.war to be created.
In addition to that, I remove <version> tag from pom.xml but still Maven is creating with war with version 1.0 by default.
My pom.xml :
<modelVersion>4.0.0</modelVersion>
<groupId>commonjerseylib</groupId>
<artifactId>commonjerseylib</artifactId>
<packaging>ear</packaging>
<name>commonjerseylib</name>
<!--<version>1.0</version>-->
How to build it without version ?
You will always need a version number for a project, however it is possible to change the name of the generated package (JAR, WAR, EAR, etc.) through the <finalName> element in the POM.
<project>
...
<build>
...
<finalName>${project.artifactId}</finalName>
...
</build>
...
</project>
or in older versions of maven:
...
<finalName>${artifactId}</finalName>
...
By default, the finalName is ${project.artifactId}-${project.version}, but this can be changed to something else. This will only affect the name of the package created in the target directory; the file name in the local repository and uploaded to remote repositories will always have a version number.
See the POM reference documentation for more information.
in maven war plugin in build, change
<warName> ${artifactId} </warName>
<build>
..........
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<!-- web.xml is not mandatory since JavaEE 5 -->
<failOnMissingWebXml>false</failOnMissingWebXml>
<warName>${artifactId}</warName>
</configuration>
</plugin>
.............
<build>
I fixed it with the below lines of code in the pom
<project>
...
<build>
...
<finalName>${project.artifactId}</finalName>
...
</build>
...
</project>

Resources