Maven - Include dependent libs in jar without unpacking dependencies? - maven-2

We're trying to build a client jar that includes unpacked dependent jar's. And the manifest should have class-path entries to the dependent jars. The snippet below works but the jars are unpacked - how can we stop the jars from being unpacked?
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>

Indeed, assembling using jar-with-dependencies causes maven to unpack all the dependencies as ${assembly.dependencySets.dependency.unpack} is set to true in the corresponding assembly descriptor.
A simple fix would be to provide an assembly descriptor similar to the jar-with-dependencies.xml and modify ${assembly.dependencySets.dependency.unpack} to false, like this:
EDIT: For an unknown reason, the behavior when using <unpack>false</unpack> is not exactly the same and it seems necessary to add <outputDirectory>/</outputDirectory> to the fileSet or you don't get the expected result.
<assembly>
<id>uberjar</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>

You can add your dependencies as jar files to your jar:
assembly-descriptor.xml
<assembly>
<id>uberjar</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>.</outputDirectory>
</fileSet>
</fileSets>
</assembly>
pom.xml
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>make-uberjar</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptor>src/main/assemble/assembly-descriptor.xml</descriptor>
</configuration>
</execution>
</executions>
</plugin>
But unfortunately you can't use the Class-Path header in manifest.mf, see Adding Classes to the JAR File's Classpath:
Note: The Class-Path header points to classes or JAR files on the local network, not JAR files within the JAR file or classes accessible over Internet protocols. To load classes in JAR files within a JAR file into the class path, you must write custom code to load those classes. For example, if MyJar.jar contains another JAR file called MyUtils.jar, you cannot use the Class-Path header in MyJar.jar's manifest to load classes in MyUtils.jar into the class path.

The solution proposed by Pascal Thivent defines a new assembly for the Maven assembly plugin. The Maven assembly plugin offers defaults assemblies which are 'bin', 'jar-with-dependencies', 'project' and 'src' producing various predefined bundles.
A new assembly has to be defined in a new xml file, most of the time located in src/assemble. Then it will be loaded instead of the predefined one, this way:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<!-- disabled predefined assembly -->
<!--
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
-->
<descriptors>
<descriptor>src/assemble/myAssembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>

Related

Custom assembly descriptor to create a jar with dependencies

I would like to generate a .jar application from a project made in Maven.
I am working in Eclipse, and I made: run as/Maven assembly:assembly
This is the error message:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.2-beta-4:assembly (default-cli) on project FeelIndexer: Error reading assemblies: No assembly descriptors found.
This is my assamble.xml
<assembly>
<id>exe</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory></outputDirectory>
<outputFileNameMapping></outputFileNameMapping>
<unpack>true</unpack>
<scope>runtime</scope>
<includes>
<include>commons-lang:commons-lang</include>
<include>commons-cli:commons-cli</include>
</includes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>target/classes</directory>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
</assembly>
I think i have to include something else for adding the dependencies of muy project, but i don't know how to do it!!
suggestions??
Update: Below my assembly.xml
<assembly>
<id>exe</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory></outputDirectory>
<outputFileNameMapping></outputFileNameMapping>
<unpack>true</unpack>
<scope>runtime</scope>
<includes>
<include>commons-lang:commons-lang</include>
<include>commons-cli:commons-cli</include>
</includes>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>target/classes</directory>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</assembly>
Where could i find my maven-assembly-plugin configuration??
I tried two options you told me:
Using predefined assembly.xml
Inserting plugin
I had the same result :s
To use a custom assembly descriptor, you have to declare it in the plugin configuration:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/src.xml</descriptor>
</descriptors>
</configuration>
[...]
</plugin>
</plugins>
</project>
By the way, wouldn't the predefined assembly jar-with-dependencies suit your needs? I don't see much differences with your custom assembly and my suggestion would be to use the predefined one:
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
[...]
</plugin>
</plugins>
</project>
Update: I don't understand what you're doing and I'm not sure you understood how the assembly plugin works.
The Maven Assembly Plugin configuration (the above samples, enclosed by <plugin>) goes in the pom.xml, not in the assembly descriptor.
If you configure the Maven Assembly Plugin to use src/main/assembly/src.xml as assembly descriptor, the file must exist (so either rename your assembly descriptor or change the configuration, the above sample was just... an example).
From what I see, you don't need a custom assembly descriptor. You could simply use the second snippet I gave in my initial answer (put it in your pom.xml).

maven-assembly plugin - how to create nested assemblies

I have a project whereby I'm trying to create a distribution zip file, which contains (amongst other files) an executable jar with dependencies of my java project.
So I sort of want it to look like this:
-wiki-search-1.0.0-dist.zip
-wiki-search.bat
-wiki-search-help.html
-wiki-search-1.0.0-jar-with-dependencies.jar
-jar content...
I'm using the assembly plugin, and the predefined descriptor "jar-with-dependencies" to create my executable jar file.
I'm specifying a separate assembly plugin entry in my pom, referencing a custom descriptor to try and build the distributable zip file.
So the part of my pom looks like this:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>quicksearch.QuickSearchApp</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>attached</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>attached</goal>
</goals>
</execution>
</executions>
</plugin>
And my custom descriptor looks like this:
<assembly>
<id>dist</id>
<formats>
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<includes>
<include>${project.basedir}/target/wiki-search-0.0.1-SNAPSHOT-jar-with-dependencies.jar</include>
</includes>
<outputDirectory>.</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/main/etc</directory>
<includes>
<include>*</include>
</includes>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
</assembly>
Everything works fine. The jar-with-dependencies is being built. My dist zip file is being built. But the dist zip file does not contain the jar-with-dependencies file.
With your existing configuration, your two separate configurations for the assembly plugin will be merged, and the configurations will also be merged.
To achieve your goal you should define a single assembly-plugin configuration with multiple nested executions, then define the configuration for each execution inside it. The assembly plugin will then execute each assembly sequentially, so the jar-with-dependencies jar will be available for inclusion in the dist jar. Also note the attached goal is deprecated in favour of the single goal.
Also note that paths in the assembly are relative to the root, and to include a particular file you should use the <files> element rather than the <filesets> element. You can also specify properties in the assembly to make it less fragile to change.
The rearranged configuration and assembly below should do what you're after:
Assembly descriptor:
<assembly>
<id>dist</id>
<formats>
<format>tar.gz</format>
<format>tar.bz2</format>
<format>zip</format>
</formats>
<files>
<file>
<source>
target/${project.artifactId}-${project.version}-jar-with-dependencies.jar
</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<includes>
<include>*</include>
</includes>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
Assembly plugin:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>quicksearch.QuickSearchApp</mainClass>
</manifest>
</archive>
</configuration>
</execution>
<execution>
<id>dist</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
You have two different configurations for the assembly plug-in, and you want them to be run in order (jar before zip), but I don't think Maven implies any order in how this will be resolved. My guess is that the zip file is being generated before the JAR file.
Even if that is not the case, I would suggest you create one module per artifact. Move the JAR assembly into its own module and have the now Zip-only module depend on it. That way Maven's dependency order resolution can kick in and build them in order.

Maven assembly plugin support Jar format?

I have configured my assembly descriptor to have an assembly of type jar by
<formats>
<format>jar</format>
</formats>
However,on running mvn install getting zip files instead of jar.Where I have gone wrong?
This configuration produces a jar assembly with the classifier jar-assembly containing only the contents of target/classes. You can add additional filesets if needed to add other content to the jar. To ensure you don't have zip archives from any previous runs in your target directory, you can delete it or run mvn clean.
<assembly>
<id>jar-assembly</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
The plugin configuration should look something like this. Note setting appendAssemblyId to false will cause the default jar to be replaced by the jar from the assembly, remove that element if this is not the desired behaviour:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/archive.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
Why don't you use the pre-defined assembly jar-with-dependencies? Below the descriptor file:
<assembly>
<id>jar-with-dependencies</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
</fileSet>
</fileSets>
</assembly>
To use assembly:assembly using a predefined descriptor, run:
mvn assembly:assembly -DdescriptorId=jar-with-dependencies
To produce the assembly as part of the normal build cycle, bind the single or single-directory mojo to the package phase (see Usage):
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</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>
[...]
</project>

How can I include unit tests in maven assembly?

Reason: Our project is using Ant as commandline interface. After making a new assembly with maven's assembly plugin, I want to make initial tests to see if all has been properly assembled. Therefore I need to include the unit tests in the final assembly. After assembling, the initial tests would then be called sth like
> ant initTest
build.xml:
<target="initTest">
<junit>
<test class="MyTest" />
</junit>
</target>
Problem is:
I want to keep my Unit tests in src/test/java and not move them to src/main/java.
Is there a way to tell the assembly plugin to include my unit tests? A simple include in the assembly descriptor does not do it ...
There are two steps:
Package the tests into a jar as well as the main code.
Depend on that "-tests" jar in the module that makes the assembly.
To package up the tests, you need to bin the jar:test-jar goal. e.g.
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<id>test-jar</id>
<phase>package</phase>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Then in the assembly module, you can depend on the resulting artifact.
<dependencies>
<dependency>
<groupid>${project.groupId}</groupId>
<artifactId>some-artifact</artifactId>
<version>${project.version}</version>
<classifier>tests</classifier>
</dependency>
</dependencies>
The key bit is the "classifier".
The answer from #Dominic-Mitchell did not work for me at all. What finally worked was adding a fileSet for the test classes to my assembly xml. Note that the fileSet directories are different! That stumped me for the longest time.
Use ${project.build.directory} for the test classes and ${project.build.outputDirectory} for the main:
<?xml version='1.0' encoding='UTF-8'?>
<assembly>
<id>toolbar-test</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/test-classes</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<scope>runtime</scope>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>**/LICENSE*</exclude>
<exclude>**/README*</exclude>
</excludes>
</unpackOptions>
</dependencySet>
<dependencySet>
<scope>test</scope>
<unpack>true</unpack>
</dependencySet>
</dependencySets>
</assembly>
Credit where credit is due - I found this solution within this blog post here: http://alexgaddie.blogspot.com/2010/02/creating-uber-jar-with-maven.html
I did not need the profile part of the blog post.
The following works for us.
pom.xml snippet:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<goals>
<goal>test-jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
assembly.xml snippet:
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<useProjectArtifact>true</useProjectArtifact>
<useProjectAttachments>true</useProjectAttachments>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
The key is the useProjectAttachments tag.

Maven creating flat zip assembly

To Maven gurus out there:
I'm trying to package non-java project artifacts (.NET) into a single zip file. I'm having 2 problems:
If I change packaging in my POM to zip <packaging>zip</packaging>, I get this error message: [INFO] Cannot find lifecycle mapping for packaging: 'zip'.
Component descriptor cannot be found in the component repository: org.apache.mav
en.lifecycle.mapping.LifecycleMappingzip. OK, no big deal - I changed it to <packaging>pom</packaging> to get rid of useless jar that is otherwise created in the target dir
My main problem is that files I'm packaging into ZIP are nested within few directories but I need put these into top directory of ZIP. Here's my assembly file:
<assembly>
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${basedir}/${project.artifactId}</directory>
<includes>
<include>**/Bin/Release/*.dll</include>
<include>**/Bin/Release/*.pdb</include>
</includes>
</fileSet>
</fileSets>
</assembly>
When I run this - I'll get ZIP file but files will be nested starting with C:\ followed by full path. To give you idea - project dumps it's binaries into the following structure
ProjectFoo\ProjectFoo\subproject1\Bin\Release\foo.dll and I need ZIP\foo.dll
Here's assembly plugin configuration:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>zip</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
Maybe I just need to use antrun and execute ant zip task?
As you've seen, there isn't a zip packaging type, so it makes sense to use pom packaging as you've chosen to.
You've encountered a bit of a hole in the assembly plugin's processing. You could resolve this by specifying multiple fileSets in the assembly with <outputDirectory>/<outputDirectory>, one for each directory you want to include, this is obviously a PITA, and probably not an acceptable solution.
An alternative approach is to use the Ant copy task to copy all the DLLs into a staging directory, then include that directory in the assembly.
The following configuration should do what you're after:
The antrun-plugin configuration:
<plugin>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<phase>process-resources</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/dll-staging">
<fileset dir="${basedir}/${project.artifactId}">
<include name="**/Bin/Release/*.dll"/>
<include name="**/Bin/Release/*.pdb"/>
</fileset>
<flattenmapper/>
</copy>
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>
The assembly:
<assembly>
<id>bin</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.build.directory}/dll-staging</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*.dll</include>
<include>*.pdb</include>
</includes>
</fileSet>
</fileSets>
</assembly>