Creating a Windows Executable from a Jar using Maven

August 7th, 2012 by

Often in the life of a developer there is the need to create a windows executable for a Java application that is build and packaged in a Jar file.

The following short example shows how to create an executable Jar first and a windows executable containing vendor information, a nice icon and other stuff afterwards by using a combination of the Maven Shade Plugin and the launch4j Plugin for Maven.


 

The Application

We’re building a simple swing application here and we’re just rendering a JColorChooser in a JDialog.

Simple Swing Application

Simple Swing Application

And that’s the code ..

package com.hascode.tutorial;
 
import javax.swing.JColorChooser;
import javax.swing.JDialog;
 
public class Main extends JDialog {
 private static final long serialVersionUID = 1L;
 private final JColorChooser cc;
 
 public Main() {
 setSize(800, 600);
 setTitle("hasCode.com launch4j Maven Tutorial");
 cc = new JColorChooser();
 add(cc);
 setDefaultCloseOperation(DISPOSE_ON_CLOSE);
 setVisible(true);
 }
 
 public static void main(final String[] args) {
 new Main();
 }
 
}

Configuring Maven

We’re using a combination of the Maven shade plugin and a specific variant of the Launch4j Maven Plugin (there are different implementations available) here. Alternatively you could replace the maven shade plugin with the Maven Assembly Plugin but I’m using the first one here I somehow like this one.

The Shade plugin assembles all dependencies into a runnable jar – the transformer adds the Main-Class header to the MANIFEST.MF.

The configuration of the Launch4j maven plugin should be self-explanatory.

For the look I’ve added an application icon in src/main/resources.

My final pom.xml looks like this one:

<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.hascode.tutorial</groupId>
<artifactId>launch4j-maven-sample</artifactId>
<version>0.0.1</version>
<name>hasCode Launch4j Maven Example</name>
<properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>2.5.1</version>
            <configuration>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
        </plugin>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-shade-plugin</artifactId>
            <version>1.7.1</version>
            <executions>
                <execution>
                    <phase>package</phase>
                    <goals>
                        <goal>shade</goal>
                    </goals>
                </execution>
            </executions>
            <configuration>
                <shadedArtifactAttached>true</shadedArtifactAttached>
                <shadedClassifierName>shaded</shadedClassifierName>
                <transformers>
                    <transformer implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
                        <mainClass>com.hascode.tutorial.Main</mainClass>
                    </transformer>
                </transformers>
            </configuration>
        </plugin>
        <plugin>
            <groupId>com.akathist.maven.plugins.launch4j</groupId>
            <artifactId>launch4j-maven-plugin</artifactId>
            <version>1.5.1</version>
            <executions>
                <execution>
                    <id>l4j-clui</id>
                    <phase>package</phase>
                    <goals>
                        <goal>launch4j</goal>
                    </goals>
                    <configuration>
                        <headerType>gui</headerType>
                        <jar>${project.build.directory}/${artifactId}-${version}-shaded.jar</jar>
                        <outfile>${project.build.directory}/hasCode.exe</outfile>
                        <downloadUrl>http://java.com/download</downloadUrl>
                        <classPath>
                            <mainClass>com.hascode.tutorial.Main</mainClass>
                            <preCp>anything</preCp>
                        </classPath>
                        <icon>src/main/resources/icon/application.ico</icon>
                        <jre>
                            <minVersion>1.6.0</minVersion>
                            <jdkPreference>preferJre</jdkPreference>
                        </jre>
                        <versionInfo>
                            <fileVersion>1.0.0.0</fileVersion>
                            <txtFileVersion>${project.version}</txtFileVersion>
                            <fileDescription>${project.name}</fileDescription>
                            <copyright>2012 hasCode.com</copyright>
                            <productVersion>1.0.0.0</productVersion>
                            <txtProductVersion>1.0.0.0</txtProductVersion>
                            <productName>${project.name}</productName>
                            <companyName>hasCode.com</companyName>
                            <internalName>hasCode</internalName>
                            <originalFilename>hasCode.exe</originalFilename>
                        </versionInfo>
                    </configuration>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
</project>

Building

Just run mvn package and you should get the desired hasCode.exe in your target directory. Trying to run the executable on a windows system could look like that:

Running the executable on a windows system

Running the executable on a windows system

Debugging Log4j

It is easy to debug your final application – just start it with the parameter “–l4j-debug” and in the same directory where the exe is located there should appear a file named launch4j.log containing some more or less useful information like this:

CmdLine:    C:\Documents and Settings\User\Desktop\hasCode.exe --l4j-debug
WOW64:        no
Check launcher:     (n/a)
64-bit search:    SOFTWARE\JavaSoft\Java Runtime Environment...
32-bit search:    SOFTWARE\JavaSoft\Java Runtime Environment...
Match:        SOFTWARE\JavaSoft\Java Runtime Environment\1.6
Match:        SOFTWARE\JavaSoft\Java Runtime Environment\1.6.0_33
64-bit search:    SOFTWARE\JavaSoft\Java Development Kit...
32-bit search:    SOFTWARE\JavaSoft\Java Development Kit...
Check launcher:    C:\Program Files\Java\jre6\bin\javaw.exe (OK)
Heap -Xms:    128 MB / 0%, Free: 211 MB, Heap size: 128 MB
Heap -Xmx:    1024 MB / 0%, Free: 211 MB, Heap size: 1024 MB

Tutorial Sources

Please feel free to to view and download the complete sources from this tutorial from my Bitbucket repository – or if you’ve got Mercurial installed just check it out with

hg clone https://bitbucket.org/hascode/launch4j-maven-example

Resources

<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.hascode.tutorial</groupId>
<artifactId>launch4j-maven-sample</artifactId>
<version>0.0.1</version>
<name>hasCode Launch4j Maven Example</name>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.5.1</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>1.7.1</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
<configuration>
<shadedArtifactAttached>true</shadedArtifactAttached>
<shadedClassifierName>shaded</shadedClassifierName>
<transformers>
<transformer
implementation=”org.apache.maven.plugins.shade.resource.ManifestResourceTransformer”>
<mainClass>com.hascode.tutorial.Main</mainClass>
</transformer>
</transformers>
</configuration>
</plugin>
<plugin>
<groupId>com.akathist.maven.plugins.launch4j</groupId>
<artifactId>launch4j-maven-plugin</artifactId>
<version>1.5.1</version>
<executions>
<execution>
<id>l4j-clui</id>
<phase>package</phase>
<goals>
<goal>launch4j</goal>
</goals>
<configuration>
<headerType>gui</headerType>
<jar>${project.build.directory}/${artifactId}-${version}-shaded.jar</jar>
<outfile>${project.build.directory}/hasCode.exe</outfile>
<downloadUrl>http://java.com/download</downloadUrl>
<classPath>
<mainClass>com.hascode.tutorial.Main</mainClass>
<preCp>anything</preCp>
</classPath>
<icon>src/main/resources/icon/application.ico</icon>
<jre>
<minVersion>1.6.0</minVersion>
<jdkPreference>preferJre</jdkPreference>
</jre>
<versionInfo>
<fileVersion>1.0.0.0</fileVersion>
<txtFileVersion>${project.version}</txtFileVersion>
<fileDescription>${project.name}</fileDescription>
<copyright>2012 hasCode.com</copyright>
<productVersion>1.0.0.0</productVersion>
<txtProductVersion>1.0.0.0</txtProductVersion>
<productName>${project.name}</productName>
<companyName>hasCode.com</companyName>
<internalName>hasCode</internalName>
<originalFilename>hasCode.exe</originalFilename>
</versionInfo>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

Tags: , , , , , , , , ,

3 Responses to “Creating a Windows Executable from a Jar using Maven”

  1. Simon Says:

    Hey,
    this is a good article. I would like to save it as a PDF or to print it out. But it’s not possible because your blog is not printerfriendly :-( . Could you provide the article as a pdf?

    Regards,
    Simon

  2. micha kops Says:

    You’re right .. the print layout is even uglier than the normal web layout.
    I’ve added some basic print styles for a more or less slightly improved print layout ;)

  3. Simon Says:

    Thanks man, that’s very useful!

Leave a Reply

Please leave these two fields as-is:

Protected by Invisible Defender. Showed 403 to 80,993 bad guys.

Search
Tags
Categories