Sometimes you have to let your subconscious chew on something for a month or two before you can digest it. Such is my relationship with Maven.
Last night I dove into Maven: The Complete Reference again with one very specific goal in mind: creating an artifact similar to what Eclipse produces when you export an executable jar with its dependencies in a directory next to it. I came up gasping for air with this solution clenched in my teeth.
The main class is a "Hello, World!" program. It prints its message through slf4j just so I'd have an excuse to bring in some dependencies. Here's the POM:
<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/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.chalcodes.fnord</groupId>
<artifactId>HelloMaven</artifactId>
<version>1.0</version>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.0.9</version>
</dependency>
</dependencies>
<build>
<sourceDirectory>src</sourceDirectory>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
</plugin>
<!-- make an executable jar *without* deps -->
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
<mainClass>fnord.Hello</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
<!-- assemble a zip file with the deps in lib/ -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
</project>
And here's the assembly descriptor it references:
<assembly>
<id>complete</id>
<formats>
<format>zip</format>
</formats>
<files>
<file>
<source>${project.build.directory}/${project.build.finalName}.${project.packaging}</source>
<destName>${project.artifactId}.${project.packaging}</destName>
<fileMode>0644</fileMode>
</file>
</files>
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>lib</outputDirectory>
</dependencySet>
</dependencySets>
</assembly>
This produces a file called HelloMaven-1.0-complete.zip. It contains a directory called HelloMaven-1.0, which in turn contains the executable HelloMaven.jar and the lib/ directory full of dependencies. The classpath in the manifest of the executable jar correctly references each dependency by its relative path.
I still need to figure out how to attach the zip file to the Maven project (if that's the right term) and automatically deploy it to my repo. But I feel like the tables have turned in my war with Maven. This will make building and deploying Weapon M a breeze, not only for me but for anyone who wants to customize it.