Lately, I changed my favoured IDE from Netbeans to IntelliJ IDEA. Happy so far, I quickly realised that building and running my JavaFX applications was limited to IDEA, only. Compared to Netbeans, IDEA 12 does not provide the ability to create self-contained and double-clickable archives out-of-the-box.
Okay, some work to do… ‘Play around with Gradle’ was an item on my todo-list, so I created an initial build.gradle, which was a really simple one-liner.
apply plugin: 'java'
But, as you might have expected, this was not the final solution, since the creation of a self-contained, double-clickable archive requires some more steps of work – at least pointing to an installed JavaFX archive, required for building.
I found the JavaFX Ant Tasks at Oracle’s website. While I was on my way leaving building projects with Ant behind, this task seemed to be the simplest way of achieving the desired aim, and – as you might know, also – Gradle can do it’s job by importing Ant tasks.
Et voilà, after some hours of studying the Gradle documentation and searching the www, I have a solution consisting of two concise files (sources can be found below):
build.gradlejavafx.xml

Presuming a project layout as shown, having these scripts in your project folder, enables you to:
- build the project with
gradle build - run the project with
gradle run(no matter, whether from console or IDEA) - install the project with
gradle installApp - run the installed application via batch-file or shell-script
- run the installed application by double-clicking the created archive
apply plugin: 'java'
apply plugin: 'application'
mainClassName = [REPLACE WITH YOUR MAIN CLASS]
def javaFxHome = "${System.properties['java.home']}";
//There seems to be an issue with Gradle detecting the JDK.
//So, we have to help a wee bit to find the ant-javafx.jar
//This may be different on your system.
def antJavaFxJar = "$javaFxHome/../lib/ant-javafx.jar"
def vendor = [REPLACE WITH VENDOR NAME]
def version = [REPLACE WITH VERSION NUMBER]
def title = [REPLACE WITH APPLICATION TITLE]
configurations {
//we do not want to have jfxrt.jar in the classpath when creating the jar,
//therefore a seperate configuration is required
providedCompile
}
//this one works with file dependencies. If you prefer
//e.g. Maven, feel free to change.
def libFolder = 'lib'
def includePattern = '*.jar'
dependencies {
providedCompile files("$javaFxHome/lib/jfxrt.jar")
compile fileTree(dir: libFolder, include: includePattern)
}
compileJava {
//add required JavaFX libs to compile classpath
sourceSets.main.compileClasspath += configurations.providedCompile
}
run {
//add required JavaFX libs to runtime classpath
classpath += configurations.providedCompile
}
//ant configuration for creating double-clickable, self-contained JAR
ant.importBuild 'javafx.xml'
ant.antJavaFxJar = antJavaFxJar
ant.mainClassName = mainClassName
ant.fallbackClassName = 'com.javafx.main.NoJavaFXFallback'
ant.distDir = libsDir
ant.distName = jar.archiveName;
ant.resourceDir = libFolder
ant.resourceIncludePattern = includePattern
ant.applicationTitle = title
ant.applicationVendor = vendor
ant.applicationVersion = version
ant.applicationClasses = sourceSets.main.output.classesDir
ant.applicationResources = sourceSets.main.output.resourcesDir
//clear existing task actions and call ant task
jar {
// reset actions
actions = []
doLast {
javafxjar.execute(); // <-- the task described in javafx.xml
}
//create some smarter looking start scripts
startScripts {
doLast {
unixScript.text = "java -jar ../lib/$jar.archiveName"
windowsScript.text = "java -jar ..\\lib\\$jar.archiveName"
}
}
<project name="JavaFXApplication"
xmlns:fx="javafx:com.sun.javafx.tools.ant">
<target name="javafxjar">
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
uri="javafx:com.sun.javafx.tools.ant"
classpath="${antJavaFxJar}"/>
<fx:application id="application"
name="${applicationTitle}"
mainClass="${mainClassName}"
fallbackClass="${fallbackClassName}"/>
<!-- show some info in gradle's output-->
<echo message="creating package: ${distName}"/>
<fx:jar destfile="${distDir}/${distName}">
<fx:application refid="application"/>
<!-- define the classpath to be placed in the manifest -->
<fx:resources>
<fx:fileset dir="${resourceDir}"
includes="${resourceIncludePattern}"/>
</fx:resources>
<manifest>
<attribute name="Implementation-Vendor"
value="${applicationVendor}"/>
<attribute name="Implementation-Title"
value="${applicationTitle}"/>
<attribute name="Implementation-Version"
value="${applicationVersion}"/>
</manifest>
<!-- describe the content to be packed -->
<fileset dir="${applicationClasses}"/>
<fileset dir="${applicationResources}"/>
</fx:jar>
</target>
</project>
Refinements for testing, integration of the Gradle Wrapper, etc. are possible, and may be described in another blog post.
Enjoy!
Pingback: Java desktop links of the week, December 24 | Jonathan Giles
Dezember 25, 2012 um 3:53 pm Uhr
I like the approach you’ve taken here. It’s also possible to get rid of the ant configuration completely. I started a blog and posted instructions here:
http://ryansblog.jptech.ca/2012/12/javafx-and-gradle.html
Februar 6, 2013 um 7:29 am Uhr
Very cool. Thanks for publishing…
März 7, 2013 um 11:03 pm Uhr
Hello,
interesting post. How would you make to have a single executable jar with all its dependencies embedded ?
Thanks