How to build and package JavaFX 2 Application with Maven

I hate Ant, and I can’t begin to work on a project that requires using it.

So like many people I want to build my brand new JavaFX 2 applications with the best toolchain available for Java : Maven.

I planned to create a custom maven-plugin to do the job, but by using existing ones we can do it.
Some things must be improved but the essential works.

The results is a zip file containing all dependencies (jar) with a jnlp file used to launch the application online or offline.

A demo application is currently visible on the JRebirth website. I used the html template generated by the javafxpackager tool.

Here you have the pom.xml file of the JavaFX application.

You can browse the svn source repository to show more information about the demo project at [source.jrebirth.org|http://source.jrebirth.org]:

The Pom that rules the maven Build pom.xml

<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>org.jrebirth.presentation</groupId>
	<artifactId>javafx2</artifactId>
	<version>1.0.0-SNAPSHOT</version>
	<name>JavaFX 2.0 Presentation</name>
	<url>http://www.jrebirth.org</url>
	<description>Interactive Presentation of JavaFX2 capabilities</de
        <!-- not used yet -->
	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
	</properties>

	<build>
               <!-- Include FXML resources -->
		<resources>
			<resource>
				<filtering>false</filtering>
				<directory>${basedir}/src/main/java</directory>
				<includes>
					<include>**/*.fxml</include>
				</includes>
			</resource>
			<resource>
				<filtering>false</filtering>
				<directory>${basedir}/src/main/resources</directory>
				<includes>
					<include>**/*.*</include>
				</includes>
			</resource>
		</resources>

		<plugins>
			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-compiler-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<source>1.7</source>
					<target>1.7</target>
					<encoding>UTF-8</encoding><!-- try to force encoding --> 
				</configuration>
			</plugin>

			<plugin>
				<groupId>org.apache.maven.plugins</groupId>
				<artifactId>maven-jar-plugin</artifactId>
				<version>2.3.2</version>
				<configuration>
					<archive>
						<manifestEntries>
							<JavaFX-Version>2.0</JavaFX-Version>
							<Main-Class>org.jrebirth.presentation.Presentation</Main-Class>
							<implementation-vendor>seb</implementation-vendor>
							<implementation-title>${project.name}</implementation-title>
							<implementation-version>1.0</implementation-version>
							<JavaFX-Application-Class>org.jrebirth.presentation.Presentation</JavaFX-Application-Class>
							<JavaFX-Class-Path>presentation-0.4.0-SNAPSHOT.jar
								jaxb-api-2.2.1.jar stax-api-1.0-2.jar activation-1.1.jar
								jaxb-impl-2.2.1.jar core-0.4.0-SNAPSHOT.jar
                                                        </JavaFX-Class-Path>
						</manifestEntries>
						<manifest>
							<addClasspath>true</addClasspath>
						</manifest>
					</archive>
				</configuration>
			</plugin>
			<plugin>
				<groupId>org.codehaus.mojo.webstart</groupId>
				<artifactId>webstart-maven-plugin</artifactId>
				<version>1.0-beta-2</version>
				<executions>
					<execution>
						<phase>package</phase>
						<goals>
							<goal>jnlp</goal> <!-- use jnlp, jnlp-inline or jnlp-single as appropriate -->
						</goals>
					</execution>
				</executions>
				<configuration>
					<!--outputDirectory></outputDirectory --> <!-- not required?? -->

					<!-- Set to true to exclude all transitive dependencies. Default is false. -->
					<excludeTransitive>false</excludeTransitive>

					<!-- The path where the libraries are stored within the jnlp structure. not required. by default the libraries are within the working directory -->
					<!-- <libPath>lib</libPath> -->
					<!-- [optional] transitive dependencies filter - if omitted, all transitive dependencies are included -->
					<!-- <dependencies> Note that only groupId and artifactId must be specified here. because of a limitation of the Include/ExcludesArtifactFilter <includes> <include>org.jrebirth:presentation</include> 
						<include>org.jrebirth:core</include> </includes> excludes> <exclude></exclude> <excludes </dependencies> -->
					<!--resourcesDirectory>${project.basedir}/src/main/jnlp/resources</resourcesDirectory --> <!-- default value -->

					<!-- JNLP generation -->
					<jnlp>
						<!-- default values -->
						<!--inputTemplateResourcePath>${project.basedir}</inputTemplateResourcePath -->
						<!--inputTemplate>src/main/jnlp/template.vm</inputTemplate --> <!-- relative to inputTemplateResourcePath -->
						<outputFile>Prez.jnlp</outputFile> <!-- defaults to launch.jnlp -->
						<!-- used to automatically identify the jar containing the main class. -->
						<!-- this is perhaps going to change -->
						<mainClass>org.jrebirth.presentation.Presentation</mainClass>
					</jnlp>

					<!-- SIGNING -->
					<!-- defining this will automatically sign the jar and its dependencies, if necessary -->
					<sign>
						<keystore>${basedir}/jrebirth.jks</keystore><!-- Used a pre-generated keystore -->
						<keypass>gojava</keypass>  <!-- we need to override passwords easily from the command line. ${keypass} -->
						<storepass>gojava</storepass> <!-- ${storepass} -->
						<!--storetype>fillme</storetype -->
						<alias>jrebirth</alias>

						<!--validity>fillme</validity -->
						<!-- only required for generating the keystore -->
						<!--dnameCn>fillme</dnameCn> <dnameOu>fillme</dnameOu> <dnameO>fillme</dnameO> <dnameL>fillme</dnameL> <dnameSt>fillme</dnameSt> <dnameC>fillme</dnameC -->
						<verify>true</verify> <!-- verify that the signing operation succeeded -->
						<!-- KEYSTORE MANAGEMENT -->
						<!-- <keystoreConfig> <delete>true</delete> delete the keystore <gen>true</gen> optional shortcut to generate the store. </keystoreConfig> -->
					</sign>

					<!-- BUILDING PROCESS -->
					<pack200>false</pack200>
					<gzip>false</gzip> <!-- default force when pack200 false, true when pack200 selected ?? -->
					<!-- causes a version attribute to be output in each jar resource element, optional, default is false -->
					<!-- <outputJarVersions>true</outputJarVersions> -->
					<!--install>false</install --> <!-- not yet supported -->
					<verbose>true</verbose>
				</configuration>
			</plugin>
		</plugins>
	</build>

	<dependencies>
		<dependency>
			<groupId>org.jrebirth</groupId>
			<artifactId>core</artifactId>
			<version>0.4.0-SNAPSHOT</version>
		</dependency>
		<dependency>
			<groupId>com.oracle.javafx</groupId>
			<artifactId>jfxrt</artifactId>
			<scope>provided</scope>
			<version>2.0</version>
		</dependency>
	</dependencies>
</project>

I choose to deploy the ”jfxrt.jar” into my maven repository to have a cross-platform build independantly of JavaFX Runtime installation.

Maven build doesn’t require Dlls (or .so files) dependencies, it just need the JavaFX api jar (jfxrt.jar), thus we can manage several javafx versions.

An alternative is to provide the jar with system scope by usin a ”JAVAFX_HOME” environment variable :

<dependency>
     <groupId>javafx</groupId>
    <artifactId>javafx</artifactId>
    <version>2.0.2</version>
    <scope>system</scope>
    <systemPath>C:/Program Files/oracle/jfx2.0/rt/lib/jfxrt.jar</systemPath><!-- should use environment variable for cross-platform-->
 </dependency>

Jnlp Template for JavaFX 2

The jnlp file template that you must use :

It could be improved by adding runtimes for all operating system.

src/main/jnlp/template.vm

<?xml version="1.0" encoding="UTF-8" ?>
<jnlp spec="1.0+" xmlns:jfx="http://javafx.com" href="Prez.jnlp">
	<!-- codebase="http://www.jrebirth.org/prez" for online-->
	<information>
		<title>${project.name}</title>
		<vendor>Sébastien Bordes</vendor>
		<homepage href="${project.url}"/>
		<description>${project.description}</description>
		<!--<description kind="short"></description>-->
		<!--<icon href="icon.png"/>-->
		<offline-allowed/>
	</information>

	<security>
		<all-permissions/>
	</security>

	<resources os="Windows" arch="x86">
		<jfx:javafx-runtime version="2.0+" href="http://download.oracle.com/otn-pub/java/javafx/javafx-windows-i586__Vlatest.exe "/>
	</resources>
	<resources os="Windows" arch="x64">
		<jfx:javafx-runtime version="2.0+" href="http://download.oracle.com/otn-pub/java/javafx/javafx-windows-x64__Vlatest.exe "/>
	</resources>

  	<resources>
		<j2se version="1.7+" />
		<property name="file.encoding" value="UTF-8"/>
		$dependencies
	</resources>

	<applet-desc  width="1024" height="768" main-class="com.javafx.main.NoJavaFXFallback"  name="${project.name}" />
	<jfx:javafx-desc  width="1024" height="768" main-class="$mainClass"  name="${project.name}" />

	<update check="background"/>
</jnlp>

Developper launching

I’m using __[e(fx)clipse|http://efxclipse.org/]__ to write code.

I launch the application from eclipse IDE, and to do the ‘Dlls” trick, I copy the bin folder (that store all Dlls) into the parent folder of the ”jfxrt.jar” stored into my maven repository.
It’s only used to launch the application from Eclipse. A better way will be to store them into the maven repository but It’s quite painful…
When you launch the jnlp file, you will use the default JavaFX runtime installed on your platform.

[((/public/javafx2/ci_cd/.Bin_Trick_m.jpg|Bin_Trick.png||Bin_Trick.png, jan 2012))|/public/javafx2/ci_cd/Bin_Trick.png]

Continuous Delivery

Then you can add a FTP transfer task into your Continuous Integration (obviously I use [jenkins for JRebirth|http://ci.jrebirth.org]) to allow continuous delivery to your favorite project.

[((/public/javafx2/ci_cd/.Continuous_Delivery_m.jpg|Continuous_Delivery.png||Continuous_Delivery.png, jan 2012))|/public/javafx2/ci_cd/Continuous_Delivery.png]

So __JavaFX 2__ ”Rocks” with __Maven__, and even with your favorite software factory tools ! (You can have a look at [JRebirth contribute|http://www.jrebirth.org/contribute.html] page to see which other softwares I use)

{{Enjoy JavaFX with Maven !!}}

[((http://www.wordle.net/thumb/wrdl/5080206/Maven_JavaFX2_Tutorial|Wordle: Maven JavaFX2 Tutorial||Wordle: Maven JavaFX2 Tutorial))|http://www.wordle.net/show/wrdl/5080206/Maven_JavaFX2_Tutorial]

Leave a Reply