Andy Moncsek is a software engineer and passionate Java developer since 2004. He enjoys programming with all kinds of JVM languages, frameworks, and operating systems. He is currently working for Trivadis AG Switzerland and in his spare time he is the project-owner and commiter of JACP (http://jacp.googlecode.com); a framework to create Rich Clients in MVC style with JavaFX 2, Spring and an Actor like component approach. Andy has posted 4 posts at DZone. You can read more from them at their website. View Full User Profile

Create JavaFX Executables with Maven

07.12.2012
| 13464 views |
  • submit to reddit

Many Java developers prefer maven to build, package and to deploy their Java applikations and would like to use maven with JavaFX. Althoug there are many examples around how to use maven with JavaFX,  there is currently not complete guide available.   Since JavaSE 7u5 JavaFX is bundled with the jdk, many things become much easier. Before this my preferred way was to install the jar in the local repository like this :

mvn install:install-file -Dfile=jfxrt.jar -DgroupId=com.oracle -DartifactId=javafx-runtime 
-Dpackaging=jar  -Dversion=2.0

Unfortunately you had to copy all *.dll's or so files to your local repository too. Now you can easilly reference the jfxrt.jar using the system scope and the ${java.home} property. With JavaSE 7u6 it will be possible to create "native bundles" for JavaFX, although these bundles are quite huge, until Java 8 and Jigsaw is not available.

Requirements:

JavaSE 7u6 , and Inno Setup 5, WiX 3.0 (for installers on Windows) for Linux, OSX see here.

The example pom.xml below will generate an executable jar file with maven, than it includes the JavaFX ANT tasks (deploy an jarSign ) to create the jnlp, the exe and so on.

<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/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.jacp.demo</groupId>
<artifactId>MyDemo</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>MyDemo</name>
<url>http://code.google.com/p/jacp</url>
<developers>
<developer>
<id>amo</id>
<name>Andy Moncsek</name>
<email>amo.ahcp@gmail.com</email>
</developer>
</developers>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<javafx.version>2.2</javafx.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<plugin>
<!-- copy all dependencies of your app to target folder-->
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.3</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<configuration>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
<goals>
<goal>copy-dependencies</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<JavaFX-Version>${javafx.version}+</JavaFX-Version>
<Main-Class>org.jacp.demo.MyMain</Main-Class>
<implementation-version>1.0</implementation-version>
<JavaFX-Application-Class>org.jacp.demo.MyMain</JavaFX-Application-Class>
<JavaFX-Class-Path>
<!-- list all your dependencies here-->
myDep1.jar myDep2.jar
</JavaFX-Class-Path>
<!-- The artifactId (name) of the jfxrt.jar ... see dependency system scope--> 
<Class-Path>javafx-${javafx.version}.jar</Class-Path>
</manifestEntries>
<manifest>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.6</version>
<executions>
<execution>
<phase>package</phase>
<configuration>
<target>
<!-- define the deploy ANT task-->
<taskdef name="jfxdeploy" classname="com.sun.javafx.tools.ant.DeployFXTask"
classpathref="maven.plugin.classpath" />
<!-- define the JarSing ANT task-->
<taskdef name="jfxsignjar" classname="com.sun.javafx.tools.ant.FXSignJarTask"
classpathref="maven.plugin.classpath" />
<jfxdeploy width="1024" height="768"
outdir="${project.build.directory}/deploy" outfile="${build.finalName}"
nativeBundles="all">
<info title="${project.name}" />
<!-- set the main class of your applcation; I had to create a Main.class (class Main extends MyMain) otherwise it will return an error on start-->
<application name="${project.name}" mainClass="com.javafx.main.Main" />
<resources>
<fileset dir="${project.build.directory}" includes="*.jar" />
<fileset dir="${project.build.directory}/dependency"
includes="*.jar" />
</resources>
<!-- set your jvm args-->
<platform javafx="${javafx.version}+">
<jvmarg value="-Xms512m" />
<jvmarg value="-Xmx1024m" />
</platform>
</jfxdeploy>
<!-- you need to generate a key yourself -->
<jfxsignjar destdir="${project.build.directory}/deploy"
keyStore="path/to/your/keystore" storePass="yourPass" alias="yourAlias"
keyPass="keyPass">
<fileset dir="${project.build.directory}/deploy"
includes="*.jar" />
</jfxsignjar>
</target>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ant-javafx</artifactId>
<version>${javafx.version}</version>
<systemPath>${java.home}/../lib/ant-javafx.jar</systemPath>
<scope>system</scope>
</dependency>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>javafx</artifactId>
<version>${javafx.version}</version>
<systemPath>${java.home}/lib/jfxrt.jar</systemPath>
<scope>system</scope>
</dependency>
</dependencies>
</plugin>
</plugins>
<finalName>YourAppName</finalName>
</build>
<dependencies>
<dependency>
<groupId>com.oracle</groupId>
<artifactId>javafx</artifactId>
<version>${javafx.version}</version>
<systemPath>${java.home}/lib/jfxrt.jar</systemPath>
<scope>system</scope>
</dependency>
</dependencies>
</project>
Published at DZone with permission of its author, Andy Moncsek. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Carl J. Mosca replied on Sat, 2012/07/21 - 6:59am

Very helpful, thank you.  

Can you provide details/sourcees for your main class?

 

Glen Mazza replied on Sun, 2012/11/04 - 8:53pm

This worked for me with no changes, thanks Andy for taking the time to write this.  Before this I was having problems where it would compile fine (because I included the javafx dependency) but running the maven exec plugin would always fail with a "Caused by: java.lang.ClassNotFoundException: javafx.scene.media.AudioClip" or similar.

I commented out the <jfxsignjar/> element in the maven-antrun-plugin though as the code generated is just for me, so I don't need it.

For this sample source file:

package glen;
import javafx.scene.media.AudioClip;
 
public class Soundtest {
 
    public static void main (String[] args) throws Exception {
        String mp3File = "file:///home/gmazza/Downloads/cowmoo.mp3";
        System.out.println(mp3File);
        AudioClip sound = new AudioClip(mp3File);
        sound.play();
        Thread.sleep(4000);
    }
}

I'd run mvn clean install as normal, then navigate to the target/deploy folder and run "java -jar Soundtest.jar" and the sound clip would work.  (The manifest file for Soundtest.jar, per Andy's pom file above, creates a dependency on the JavaFX jar and also places that jar in the deploy folder, so Soundtest will run fine from that folder.)  Note I found the Thread.sleep(xxx ms) above necessary else the program will terminate without the sound being played.

Andy Moncsek replied on Fri, 2012/11/09 - 4:08am in response to: Glen Mazza

@Glen

You are right, the JavaFX.jar was created because i did not excluded it. I have found a better solution which you can find here : http://code.google.com/p/jacp/source/browse/trunk/JacpFX-quickstart/pom.xml .  If you are intrested try the JacpFX archetype. It creates a compleate JacpFX project which works on top of JavaFX and Spring. The Archetype includes all goodies like native builds, fxml-, JavaFX-components (in the mix), localisation, css, etc. only tzhe native CSS compilation is uncommented at rthe moment because of a bug in JavaFX bundeling. If you are intrested take a look here: http://code.google.com/p/jacp/wiki/JacpFXTutorial or simply execute : 

mvn archetype:generate -DarchetypeGroupId=org.jacp -DarchetypeArtifactId=JacpFX-quickstart-archetype -DarchetypeVersion=1.1 -DarchetypeRepository=http://developer.ahcp.de/nexus/content/repositories/jacp

Andy Moncsek replied on Fri, 2012/11/09 - 4:10am in response to: Carl J. Mosca

Hi Carl,

yes... take a look here: http://code.google.com/p/jacp/wiki/JacpFXTutorial or simply try :

mvn archetype:generate -DarchetypeGroupId=org.jacp -DarchetypeArtifactId=JacpFX-quickstart-archetype -DarchetypeVersion=1.1 -DarchetypeRepository=http://developer.ahcp.de/nexus/content/repositories/jacp


Andy

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.