Create JavaFX Executables with Maven
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>
(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 :
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 :
Andy