Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Custom maven assembly

I'm starting to work with Maven but am not yet successfully thinking in Maven's terms. I have a specific requirement and the docs aren't giving me enough clues, so I could use a bit of help:

I'd like to create an assembly that

  1. builds a jar-with-dependencies like the "standard" target of this name, but excluding a couple of the resources. I want log4j.properties and a couple of other configuration files to not be in the jar.

  2. builds a .ZIP file containing in its root directory the .jar from step 1 as well as the above mentioned config files.

I want to fire this assembly up from the command line (only), hence no need to tie to a phase (or goal? mojo?). Preferrably using either assembly:assembly or assembly:single.

  • Do I need a custom assembly descriptor for this?
  • And is it true I can't nest it in the pom.xml? So it goes in src/assembly/something.xml and gets referenced with a descriptorRef?
  • Can I code this as two relatively simple assemblies, of which one builds on the other (i.e. the .Zip assembly uses the .Jar assembly) or do I have to do everything in one assembly?
like image 587
Carl Smotricz Avatar asked Aug 16 '10 13:08

Carl Smotricz


1 Answers

I'm starting to work with Maven but am not yet successfully thinking in Maven's terms.

Welcome on board, Carl! :D

I want to fire this assembly up from the command line (only), hence no need to tie to a phase (or goal? mojo?). Preferrably using either assembly:assembly or assembly:single.

Just to clarify: the build lifecycle itself is made of phases (compile, test, package, etc) and plugin goals (technically Mojos) are bound on phases. You then either invoke a phase... or just a specific plugin goal.

Do I need a custom assembly descriptor for this?

Well, since you want behavior that the pre-defined descriptors don't cover, yes. You'll even need two of them (of for the uberjar, one for the zip).

And is it true I can't nest it in the pom.xml? So it goes in src/assembly/something.xml and gets referenced with a descriptorRef?

Yes, that's true (descriptors use a custom format) and they usually go into src/main/assembly. And no, descriptorRef is for the built-in descriptors, you'll have to use descriptor here.

Can I code this as two relatively simple assemblies, of which one builds on the other (i.e. the .Zip assembly uses the .Jar assembly) or do I have to do everything in one assembly?

As hinted, you'll need two assembly descriptors. Let me help a bit...

Let's assume you have the following project structure:

$ tree .
.
├── pom.xml
└── src
    ├── main
    │   ├── assembly
    │   │   ├── jar.xml
    │   │   └── zip.xml
    │   ├── java
    │   │   └── com
    │   │       └── stackoverflow
    │   │           └── App.java
    │   └── resources
    │       └── log4j.properties
    └── test
        └── java
            └── com
                └── stackoverflow
                    └── AppTest.java

Where the pom.xml contains the following configuration for the assembly plugin:

<project>
  ...
  <dependencies>
    ...
  </dependencies>
  ...
  <build>
    <plugins>
      <plugin>
        <artifactId>maven-assembly-plugin</artifactId>
        <version>2.2-beta-5</version>
        <configuration>
          <descriptors>
            <descriptor>src/main/assembly/jar.xml</descriptor>
            <descriptor>src/main/assembly/zip.xml</descriptor>
          </descriptors>
        </configuration>
      </plugin>
    </plugins>
  </build>
</project>

The descriptor for the "filtered" uberjar (jar.xml) looks like this:

<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>uberjar</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <unpack>true</unpack>
      <scope>runtime</scope>
      <useProjectArtifact>false</useProjectArtifact>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <directory>${project.build.outputDirectory}</directory>
      <outputDirectory>/</outputDirectory>
      <excludes>
        <exclude>log4j.properties</exclude>
      </excludes>
    </fileSet>
  </fileSets>
</assembly>

What this descriptor does is (in short):

  • include the dependencies, unpack them, but exclude the project itself (yes, this is counter intuitive but this weird default behavior has been kept for backward compatibility)
  • include the project files but exclude some of them.

And the descriptor for the zip (zip.xml) looks like this:

<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>
  <formats>
    <format>zip</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <fileSets>
    <fileSet>
      <directory>${project.basedir}/src/main/resources</directory>
      <outputDirectory/>
      <includes>
        <include>log4j.properties</include>
      </includes>
    </fileSet>
    <fileSet>
      <directory>${project.build.directory}</directory>
      <outputDirectory/>
      <includes>
        <include>*-uberjar.jar</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

Which is (somehow) self explaining :)

  • it includes the configuration files (relatively to <directory>) at the root of the assembly
  • it includes the uberjar (relatively to <directory>) at the root of the assembly

Finally, just run mvn assembly:assembly (that's the goal intended to be used on the CLI).


I didn't (knowingly) include META-INF/maven/** in the assembly for the uberjar. Is there a simple way to prevent inclusion of these?

These are coming from the libraries that are unpacked. You can exclude them using unpackOptions. Here is a modified version of the jar.xml:

<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>uberjar</id>
  <formats>
    <format>jar</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <unpack>true</unpack>
      <scope>runtime</scope>
      <unpackOptions>
        <excludes>
          <exclude>META-INF/maven/**</exclude>
        </excludes>
      </unpackOptions>
      <useProjectArtifact>false</useProjectArtifact>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <directory>${project.build.outputDirectory}</directory>
      <outputDirectory>/</outputDirectory>
      <excludes>
        <exclude>log4j.properties</exclude>
      </excludes>
    </fileSet>
  </fileSets>
</assembly>
like image 181
Pascal Thivent Avatar answered Oct 05 '22 23:10

Pascal Thivent