Maven building jar: merge duplicate resources from dependencies - maven

I'm getting this problem:
I have a project with spring-boot. It works perfectly on eclipse, but I need to generate a jar with dependencies, so I add the maven-assembly-plugin configuration to the pom.
Some spring dependencies has in the META-INF a file called spring.schemas, and I need to merge all spring.schemas into one (spring-context, spring-beans, etc)
I tried this solution using maven-shade-pluggin and AppendingTransformer, and it merges all spring.schemas perfectly... But it has an issue, when I execute the jar, it fails with:
java.lang.IllegalStateException: Unable to open nested entry 'lib/spring-boot-starter-batch-1.2.4.RELEASE.jar'.
It has been compressed and nested jar files must be stored without compression.
Please check the mechanism used to create your executable jar file
So, shade plugin compress the jar, and spring-boot doesn't like it, and there's no way to turn off the compression in shade. I manually copy the shade spring.schemas generated by shade and I put it in the maven-assembly-pluggin generated and uncompressed jar with dependencies. It works.
Then I tried to include the generated spring.schemas into my resources folder, but it's allways overrided by the spring.schemas from spring-context.
I also tried this other solution to exclude spring.schemas from dependency jar using a descriptor XML in assembly, but it doesn't work:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
<id>distribution</id>
<formats>
<format>jar</format>
</formats>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<includes>
<include>org.springframework:spring-context</include>
</includes>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>**/spring.schemas</exclude>
</excludes>
</unpackOptions>
</dependencySet>
<dependencySet>
<outputDirectory>/</outputDirectory>
<excludes>
<exclude>org.springframework:spring-context</exclude>
</excludes>
<unpack>true</unpack>
</dependencySet>
</dependencySets>
</assembly>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>org.springframework.batch.core.launch.support.CommandLineJobRunner</mainClass>
</manifest>
<compress>false</compress>
</archive>
<descriptors>
<descriptor>src/main/assembly/distribution.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
This are my dependencies:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-batch</artifactId>
</dependency>
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
</dependency>
<!-- MySql 5.5 Connector -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.35</version>
</dependency>
</dependencies>
Any ideas? Thanks in advance

You can use maven-assembly-plugin.
Add the plugin to your pom.xml:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>fat-jar.xml</descriptor>
</descriptors>
</configuration>
</plugin>
Add a fat-jar.xml descriptor next to your pom.xml:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>fat</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<containerDescriptorHandlers>
<containerDescriptorHandler>
<handlerName>metaInf-spring</handlerName>
</containerDescriptorHandler>
</containerDescriptorHandlers>
</assembly>
Notice the metaInf-spring handler. It will merge any META-INF duplicate files having names starting with the spring word.
The reference documentation: https://maven.apache.org/plugins/maven-assembly-plugin/examples/single/using-container-descriptor-handlers.html

Instead of using maven-assembly-plugin and maven-shade-pluggin, I would try to use Spring Boot's own spring-boot-maven-plugin that can be used to create an executable ‘fat’ JAR. See this reference documentation page, section "73.2 Create an executable JAR with Maven".
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
Or, if you don't use the spring-boot-starter-parent POM:
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>1.2.5.RELEASE</version>
<executions>
<execution>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>

Related

maven assembly plugin: descriptorRef not using basedir

I am using maven assembly plugin to zip my web application dist folder.
I use this descriptorRef file:
<assembly>
<id>webapp-build</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>dist</directory>
<outputDirectory>.</outputDirectory>
<includes>
<include>**/*</include>
</includes>
</fileSet>
</fileSets>
</assembly>
and I use it as a dependency in a parent pom like this:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<dependencies>
<dependency>
<groupId>com.company</groupId>
<artifactId>build-tools</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<executions>
<execution>
<id>webapp-build</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptionRef>webapp-build</descriptionRef>
</descriptorRefs>
<basedir>${project.assembly.directory}</basedir>
</configuration>
</execution>
</executions>
</plugin>
Depending on the child using this parent pom, I would like to tell in which directory, the maven assembly plugin has to use the webapp-build assembly descriptor. I tried with <basedir> attribute but it is not using it. Any ideas ?
The descriptorRef is intended to load assembly descriptors from classpath or using predefined descriptors. If you like to use the given descriptor you have to use descriptors instead like this:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assemblies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Furthermore a basedir configuration element does not exist for maven-assembly-plugin:single
<basedir> isn't a parameter of assembly:single. There's descriptorSourceDirectory:
descriptorSourceDirectory:
Directory to scan for descriptor files in. NOTE: This may not work correctly with assembly components.

Package provided dependencies in a single zip file

I have put dependency jars in separate folder but expecting folder should be zipped instead of direct folder. I tried using assembly descriptor but it is creating separate folder with dependencies but not zipping it (folder should not be there, only zip file is expected). Please suggest me better approach to accommodate my dependency jars in a single zip file
pom.xml
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.9</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeScope>provided</includeScope>
<outputDirectory>/Users/venugopal/Documents/providedDependencies</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/assembly/archive_format.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- append to the packaging phase. -->
<goals>
<goal>single</goal> <!-- goals == mojos -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
archive_format.xml (Assembly descriptor
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<baseDirectory>/</baseDirectory>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>/Users/vp/Documents/providedDependencies</directory>
</fileSet>
</fileSets>
</assembly>
If I understand your requirement right, you want to package all provided dependencies into a zip file.
You are headed the wrong way using maven-dependency-plugin. You should use maven-assembly-plugin and its dependencySet:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<baseDirectory>/</baseDirectory>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<scope>provided</scope>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
</assembly>
Setting the scope to provided will make sure only the provided dependencies are considered in this set. We need to exclude the project artifact, otherwise it will be included by default.

Assembly plugin generating 2 jars. One with classfiles. One with dependencies

I am having trouble building a jar using the assembly plugin. I have a bunch of system jar files that I want bundled alongside class files of the project.
I was looking to do something like:
final
- lib
- system.jar
- system1.jar
- com
- servlet
-- etc
I have tried to use the assembly plugin but it generates 2 jars. One with just the lib with my jars and another with the class files.
I have read through the assembly docs but I must be missing something.
Here is the build element I have in my pom.xml
<dependency>
<groupId>jackson-mapper-asl</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.4</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/jackson-mapper-asl-1.9.4-sc1.jar</systemPath>
</dependency>
//... etc
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>final-jar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
This is my assembly file (assembly.xml)
<assembly>
<id>distribution</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<useTransitiveDependencies>true</useTransitiveDependencies>
<unpack>false</unpack>
<scope>system</scope>
<outputDirectory>lib</outputDirectory>
<includes />
</dependencySet>
</dependencySets>
</assembly>
Any idea how I can merge these jars together?
You would usually have a much simpler layout, such as:
final
- lib
-system.jar
-system1.jar
-project.jar
I.e. the project itself is a jar too, and included in the lib. In this case just add <useProjectArtifact>true/>useProjectArtifact> to the dependencySet.
If you really, really want to have classes copied in directly, try adding a fileset to the assembly, copying from target/classes into your root location
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>

Package Dll in Jar using Maven- single goal

I have added a DLL in my maven project as dependency like this :
<dependency>
<groupId>com.test.dll</groupId>
<artifactId>myDll</artifactId>
<version>0.1</version>
<type>dll</type>
</dependency>
When I try to execute maven:install
It is giving me this error:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.2-
beta-5:single (jar-with-dependencies) on project testApp: Failed to create
assembly: Error adding file-set for 'com.test.dll:myDll:dll:0.1' to archive: Error
adding archived file-set. PlexusIoResourceCollection not found for: C:\Users\USER\.m2
\repository\com\test\dll\myDll\0.1\myDll-0.1.dll: No such archiver: 'dll'
What Am I doing wrong here??
Update
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>sign</goal>
</goals>
</execution>
</executions>
<configuration>
<keystore>src/main/keystore/mykey.keystore</keystore>
<alias>aliasname</alias>
<storepass>passw0rd</storepass>
<verify>true</verify>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
The problem here is the jar-with-dependencies descriptor. The descriptor unpacks all dependencies into a directory and packages this directory into a new JAR file. However, it cannot unpack a DLL file (that's the "No such archiver" error message). To get this working, you need to define your own assembly descriptor:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>assembly-with-dll</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<!-- package the regular dependencies -->
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<unpack>true</unpack>
<scope>runtime</scope>
<!-- exclude the DLL -->
<excludes>
<exclude>com.example:my-dll</exclude>
</excludes>
</dependencySet>
<!-- package the DLLs -->
<dependencySet>
<outputDirectory>/</outputDirectory>
<includes>
<include>com.example:my-dll</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
Provided, that the descriptor above resides in src/main/assembly, the configuration of the maven-assembly-plugin looks as follows:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptor>src/main/assembly/assembly.xml</descriptor>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
There is a piece of information here : Maven Dll Dependency Problem.
To solve this issue, exlude dll from your assembly :
<excludes>
<exclude>*:dll*</exclude>
</excludes>
Last time I had to create a executable jar with dependencies, I put them out of the jar, in a lib directory.
DLL must be :
either in application classpath (like server/lib for a server)
or in the OS classpath (C:\Windows\system32 for instance)
After reading your pom and dependecy file set, I may be able to be more accurate :)
To add to Stefan's answer, I don't think you want to do a jar-with-dependencies packaging for this project of yours. You should look at using one of the bin packaging (like .zip or tar.gz)

maven assembly dir with a jar dependency from project

I am trying to use maven to assemble a directory for a install package. The install package requires several things: configuration files, dependency libraries and an executable jar of my class files. I am having trouble figuring out how to add the executable jar.
Here is what I have so far:
<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.myproject</groupId>
<artifactId>myproject</artifactId>
<version>8.1.1</version>
<name>my project</name>
<packaging>pom</packaging>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.2</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<configuration>
<descriptor>${basedir}/src/main/assembly/client.xml</descriptor>
</configuration>
<executions>
<execution>
<id>create-client</id>
<configuration>
<descriptor>${basedir}/src/main/assembly/client.xml</descriptor>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
.
.
.
</dependencies>
</project>
Then my assembly descriptor looks like this:
<assembly>
<id>client</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${basedir}/src/main/reports</directory>
<outputDirectory>/reports</outputDirectory>
</fileSet>
<fileSet>
<directory>${basedir}/src/main/resources/audio</directory>
<outputDirectory>/audio</outputDirectory>
</fileSet>
<fileSet>
<directory>${basedir}/src/main/client</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
</assembly>
If i call mvn assembly:assembly I get a directory with all the libraries and configuration files. Works great.
But now I want to add an executable jar of all my compiled code. I can create this jar alone by adding this to my pom and calling mvn jar:jar
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<finalName>run</finalName>
<archive>
<manifest>
<mainClass>com.myproject.main.StartProcess</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
The question is, how can I get that jar into my assembly automatically?
I have tried a couple things but I have no idea where to start. Can I somehow call the jar execution from my assembly?
Any help appreciated.
I think you should turn your useProjectArtifact to true (this is the default value).
It determines whether the artifact produced during the current project's build should be included in this dependency set.

Resources