views:

197

answers:

1

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?
+4  A: 

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"&gt;
  <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"&gt;
  <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"&gt;
  <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>
Pascal Thivent
Salut Pascal, thank you *very* much for this tremendously helpful answer! I was hoping you'd respond, I had even considered contacting you directly. "On board" may be a bit of an overstatement: A large variety of disasters, seemingly random, have plagued my build ever since I started trying to run it in Maven. I still feel Maven has a face only a mother could love. But in trusting your judgement, among others, I'm continuing to tough it out and hope to hit a plateau in the learning curve before my patience gives out ;)
Carl Smotricz
@Carl I was wondering if someone was forcing you to use Maven, maybe holding your family in hostage :) More seriously, congrats for the initiative and if I can make *your* experience a bit better, I'll be happy to help.
Pascal Thivent
The "hostage" guess is roughly correct - this is a job-work project. Works like a charm, BTW. Thanks again. Is there a way I can influence the `-bin` suffix on the `.zip`?
Carl Smotricz
@Carl Bwuhahah :) Regarding the suffix, it comes from the assembly `<id>`.
Pascal Thivent
Stupid me, that's the one place I forgot to look. Thanks!
Carl Smotricz
@Pascal: I didn't (knowingly) include `META-INF/maven/**` in the assembly for the uberjar. Is there a simple way to prevent inclusion of these? I found the element `repositories/repository/includemetaData` but don't see a way to apply it.
Carl Smotricz
@Carl See my update.
Pascal Thivent
@Pascal: Thanks for your latest update, in case I forgot. I thought you might be pleased to hear that I was just approached by a colleague who (slightly tongue in cheek) called me a maven guru and asked for my help doing something in maven. I was in the position of knowing that maven indeed offers the functionality he wanted, and was able to show him the relevant pages in my MtDG. You helped make this surprising turn of events possible. :)
Carl Smotricz
@Carl You're welcome and thanks for the feedback. Regarding the last part, let me tell you that I'm particularly proud of that :)
Pascal Thivent
@Pascal @Carl, I will have to agree Pascal is quite helpful. I was wondering if you could give me some information on how you could add *.zip files into assemblies and have them expanded with this plugin.
garbagecollector
@garbagecollector If these `.zip` files are not dependencies but files inside a project gathered with `fileSets`, I don't think you'll be able to unpack them. At least not with the assembly plugin. Is there any question where I could elaborate more easily?
Pascal Thivent