Wednesday, March 13, 2013

Bending Maven to my will

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.

No comments:

Post a Comment