Oct 10, 2010

Assemble executable JAR with dependencies using Maven

Problem description: As a result of the build process I need following artifacts to be generated and packed into single ZIP archive:
  • JAR with all compiled classes and resources
  • Manifest file with properly configured main class and generated class path
  • all dependencies
This archive could be unpacked and executed with double click on the application jar file or with simple java -jar command.
This problem could be easily solved with Apache Maven build manager.

We need to use and configure following plugins:

Configuration of the maven-jar-plugin:
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-jar-plugin</artifactId>
                <configuration>
                    <archive>
                        <addMavenDescriptor>false</addMavenDescriptor>
                        <compress>true</compress>
                        <manifest>
                            <addClasspath>true</addClasspath>
                            <classpathPrefix>libs/</classpathPrefix>
                            <mainClass>com.mightypocket.ashoter.Main</mainClass>
                        </manifest>
                    </archive>
                </configuration>
            </plugin>

This plugin creates a jar file for your application. This jar file contains all compiled classes and resources. One very important part of this file is a manifest. To make it possible to be executed without additional configurations it has to have classpath and mainclass entries. There are several options with class path. In the preceding example all libraries are prefixed with "libs/". It gives us an ability to put all required libraries into separated folder "libs".

Configuration for the maven-dependency-plugin.
           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/libs</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>

This plugin does all dirty work finding and coying all direct and transitive dependencies of the application. Those libraries will be copied into specified folder, "libs" in our case.

Configuration for the maven-assembly-plugin.
           <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptors>
                        <descriptor>assembly/bin.xml</descriptor>
                    </descriptors>
                    <finalName>AndroidScreenCapture_${project.version}</finalName>
                    <outputDirectory>${project.build.directory}/dist</outputDirectory>
                    <workDirectory>${project.build.directory}/assembly/work</workDirectory>
                </configuration>
            </plugin>
The last but not least plugin - Assembly. It put all parts together and puck them into archive. It needs an assembly descriptor to do its job. In this case the descriptor is very simple one:

<assembly>
    <id>bin</id>
    <formats>
        <format>zip</format>
    </formats>
    <filesets>
        <fileset>
            <includes>
                <include>README*</include>
                <include>LICENSE*</include>
                <include>NOTICE*</include>
            </includes>
        </fileset>
        <fileset>
            <directory>target</directory>
            <outputDirectory></outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileset>
        <fileset>
            <directory>target/libs</directory>
            <outputDirectory>libs</outputDirectory>
            <includes>
                <include>*.jar</include>
            </includes>
        </fileset>
    </filesets>
</assembly>

2 comments:

flashsnake said...

Please change to and to

Chandrasing said...

XML tags are not in camel case format. please fix that.