I would like to build two different versions of a WAR in Maven (I know that's a no-no, that's just the way it is given the current situation). In the version of a WAR depicted by an assembly, I want to replace a dependency by the same dependency with a different classifier. For example, I was expecting this assembly to work:
<assembly>
<id>end-user</id>
<formats>
<format>war</format>
</formats>
<dependencySets>
<dependencySet>
<excludes>
<exclude>group:artifact:jar:${project.version}</exclude>
</excludes>
<includes>
<include>group:artifact:jar:${project.version}:end-user</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
This doesn't work, but am I heading in the right direction? I've already read all the pages on the Maven assembly page and the section on the Maven Definitive Guide that seems relevant. Any pointers would be helpful.
Personally, I think that the cleanest solution would be to use two profiles (one of them depending on the artifact with the classifier, the other on the "regular" artifact). But you can indeed achieve what you want with a custom assembly. I just don't think you're heading in the right direction. Here is how I would do it...
First, create a specific project for the assembly and declare both the webapp and the artifact with the classifier as dependencies. Something like this:
<project>
...
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>artifact</artifactId>
<version>${project.version}</version>
<classifier>end-user<classifier>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>zewebapp</artifactId>
<version>${project.version}</version>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/end-user.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>
</project>
Then, in your assembly descriptor:
<assembly>
<id>end-user</id>
<formats>
<format>war</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>**/artifact-*.jar</exclude>
</excludes>
</unpackOptions>
<includes>
<include>*:war</include>
</includes>
</dependencySet>
<dependencySet>
<unpack>false</unpack>
<outputDirectory>WEB-INF/lib</outputDirectory>
<includes>
<include>group:artifact:jar:*:end-user</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
Basically, this tells the assembly plugin to get the war for zewebapp and to unpack it but to exclude the unwanted artifact while unpacking. Then, the assembly plugin get the artifact with the classifier and place it in WEB-INF/lib (so we substitute it to the original). Finally, the whole thing is packaged as a war.
I tested this on a simplified example, it should work.
The "version" information is not required when specifying artifact coordinates for includes/include*.
This should work:
<assembly>
<id>end-user</id>
<formats>
<format>war</format>
</formats>
<dependencySets>
<dependencySet>
<includes>
<include>group:artifact:jar:end-user</include>
</includes>
</dependencySet>
</dependencySets>
</assembly>
I think the maven assembly documentation for the includes/include* section is incorrect. It says "Artifact coordinatess may be given in simple groupId:artifactId form, or they may be fully qualified in the form groupId:artifactId:type:version[:classifier]." However, from my testing, the "version" is not required. I got the hint from here.
Took me while to find out, thought might be useful to others in the future.
Related
I'm trying to set up a project using Maven and am a bit stuck with how to include some third party dependencies that need to be included unpacked in the resultant war file.
My project contains some custom ColdFusion code and includes Java dependencies, including ColdFusion packaged as a war file. I then am attempting to include some 3rd party ColdFusion code, which I've installed in my maven repository packaged as a jar, but I actually want to deploy it unpacked in the resultant war file. It's this unpacking of the 3rd party libraries that I'm stuck with. I'd really like this to be done BEFORE the war is build, so that I can use war:exploded during the development.
Currently my pom.xml looks something 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>com.mycompany.app</groupId>
<artifactId>my-webapp</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>my-webapp Maven Webapp</name>
<url>http://maven.apache.org</url>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- This is the war overlay -->
<dependency>
<groupId>com.adobe.coldfusion</groupId>
<artifactId>coldfusion</artifactId>
<version>9.0.1</version>
<type>war</type>
<scope>runtime</scope>
<optional>false</optional>
</dependency>
<!-- This is the 3rd party ColdFusion dependency -->
<dependency>
<groupId>org.corfield</groupId>
<artifactId>fw1</artifactId>
<version>1.2RC2A</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>my-webapp</finalName>
</build>
</project>
I've kind of got it doing what I want by modifying the build section as follows:
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>org.corfield</groupId>
<artifactId>fw1</artifactId>
<version>1.2RC2A</version>
<type>jar</type>
<overWrite>true</overWrite>
<outputDirectory>${project.build.directory}/${project.artifactId}</outputDirectory>
<includes>**/*.cfc</includes>
</artifactItem>
</artifactItems>
<includes>**/*.cfc</includes>
<outputDirectory>${project.build.directory}/${project.artifactId}</outputDirectory>
<overWriteReleases>false</overWriteReleases>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The problem with this is that the package:unpack happens after the war is built, so the unpacked dependecies are not in the resulting war file.
I have also tried a few things with the assembly plugin and I came fairly close also by using something like this:
<assembly>
<id>${project.artifactId}</id>
<formats>
<format>war</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<includes>
<include>org.corfield:fw1</include>
</includes>
<unpack>true</unpack>
<outputDirectory>/</outputDirectory>
</dependencySet>
<dependencySet>
<excludes>
<exclude>org.corfield:fw1</exclude>
</excludes>
<unpack>false</unpack>
<outputDirectory>/WEB-INF/lib</outputDirectory>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>src/main/webapp</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
However that created a second war file named something like my-webapp-1.0-SNAPSHOT-my-webapp.war as well as the my-webapp-1.0-SNAPSHOT.war. The my-webapp-1.0-SNAPSHOT-my-webapp.war also included my-webapp-1.0-SNAPSHOT.war
At the end of the day I want my resultant war to look like:
org
|-- corfield
|-- framework.cfc
WEB-INF
|-- lib
|-- web.xml
index.cfm
(in reality there's a lot more to it than that, but that's enough to illustrate the point hopefully)
I think I'm pretty close but I'm just missing something I need. I'd be extremely grateful for any assistance.
For the maven-dependency-plugin approach, bind the unpack goal on the prepare-package phase (Maven 2.1+) instead of package.
References
Lifecycle Reference
Have you looked at the overlay option with maven-war-plugin? It esstentially allows you to unpack the ColdFusion war on top your site layout. I've done this with a combination of ColdFusion 9.x and Struts2. Doing a ColdFusion only overlay should make it real easy. You may want to create the ColdFusion war first. You can also then control the neo-*.xml files from your Maven project as well.
I'm building a multi-module Maven project whose major product is a WAR file, and I'm trying to assemble that file together with associated release-related artifacts (README, release notes, license file, etc.) into a ZIP for distribution. But when I try to build a distribution file, it fails. What am I doing wrong? Note that I have already checked that the foo-bar.1.0.war artifact exists at the point that the foo-distribution module is asked to build the distribution file; I'm aware that putting everything in foo's POM won't work. (I have a workaround; I can use relative paths to point directly to the location of the files distributed relative to the foo-distribution module root. This isn't a solution I like as it has bad code-smell.)
Note also that I always build from the root project, and that I'm using assembly:single in the distribution builder (as recommended in the Maven documentation).
Project Layout
foo
+ src
| + README.txt
+ foo-bar
| + target
| + foo-bar.1.0.war
+ foo-distribution
+ src
+ assemble
+ dist.xml
foo and foo-distribution have pom packaging, and foo-bar has war packaging. (There are other modules in the real code, but they're also constructed correctly before the foo-distribution module.)
foo POM
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<groupId>foobar</groupId>
<artifactId>foo</artifactId>
<packaging>pom</packaging>
<version>0.0.1-SNAPSHOT</version>
<modules>
<module>foo-bar</module>
<module>foo-distribution</module>
</modules>
</project>
foo-distribution POM
<project xmlns="http://maven.apache.org/POM/4.0.0">
<modelVersion>4.0.0</modelVersion>
<version>0.0.1-SNAPSHOT</version>
<parent>
<artifactId>foo</artifactId>
<groupId>foobar</groupId>
<version>0.0.1-SNAPSHOT</version>
<relativePath>..</relativePath>
</parent>
<groupId>foobar</groupId>
<artifactId>foo-distribution</artifactId>
<packaging>pom</packaging>
<dependencies>
<dependency>
<groupId>foobar</groupId>
<artifactId>foo-bar</artifactId>
<version>1.0</version>
<type>war</type>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2-beta-5</version>
<configuration>
<finalName>foobar</finalName>
<descriptors>
<descriptor>src/assemble/dist.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-t2server-distribution</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
dist.xml
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0">
<id>distribution</id>
<formats>
<format>zip</format>
</formats>
<moduleSets>
<moduleSet>
<includes>
<include>foobar:foo</include>
</includes>
<sources>
<fileSets>
<fileSet>
<directory>src</directory>
<includes>
<include>*.txt</include>
</includes>
</fileSet>
</fileSets>
</sources>
</moduleSet>
<moduleSet>
<includes>
<include>foobar:foo-bar</include>
</includes>
<binaries />
</moduleSet>
</moduleSets>
</assembly>
Workaround dist.xml
This is the workaround that I mentioned above. It produces exactly the artifact that I want.
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0">
<id>distribution</id>
<formats>
<format>zip</format>
</formats>
<fileSets>
<fileSet>
<directory>${project.basedir}/../src</directory>
<includes>
<include>*.txt</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.basedir}/../foo-bar/target</directory>
<includes>
<include>*.war</include>
</includes>
<outputDirectory>.</outputDirectory>
</fileSet>
</fileSets>
</assembly>
You should use a dependencySet in your assembly descriptor
<assembly>
<id>dist</id>
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<dependencySets>
<dependencySet>
<useTransitiveDependencies>false</useTransitiveDependencies>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
<scope>runtime</scope>
<fileMode>0644</fileMode>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
with all supplemental files you need
</fileSet>
</fileSets>
instead of referencing the files via file system (relative paths). And on the other hand a descriptor for source does exists already from the assembly plugin (take a look into the docs).
What order are the modules being build, I had a similar problem and declaring what the parent was in the child module helped with the build order. Not sure if using could help with this.
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).
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>
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.