IntelliJ IDEA Java

IntelliJ IDEA and JavaFX

This week we’re doing a Live Stream on JavaFX, and I wanted to use that opportunity to refresh my JavaFX knowledge.

I’ve been using JavaFX in a number of my demo applications over the last six years, and the one thing I’ve learnt is that it’s a bit of a moving target, in particular since JavaFX was taken out of the JDK in Java 11. What I wanted to find out is what’s the current best way to create a new JavaFX application, and how do you run it from inside IntelliJ IDEA?

Build Tools & JavaFX

JavaFX is not quite as simple a dependency as any other library you might be using in your applications. We can’t just add a new dependency in our Maven or Gradle file and start using it straight away. This is mostly because UI frameworks depend more upon your operating system than other sorts of frameworks, so the build tool needs to pull in the correct dependency for your OS.

Having worked with both Maven and Gradle in my JavaFX applications, I’ve seen the approaches both tools take. Since both build tools are popular, I wanted to cover both of them.

JavaFX with Gradle

These example applications were all started by following the OpenJFX Getting Started Documentation on the openjfx site, any differences between that guide, and the final code are documented.

Using the Java Module System

Example application code here

If you want a seamless experience working with IntelliJ IDEA, JavaFX and Gradle, and you are free to make all the architectural decisions, try creating a modular application using Java’s Module System (introduced in Java 9). The only real impact on a small application like the demo app we’re writing here is one additional file, module-info.java.

There are a number of subtleties for working with modules, which I won’t cover in this example. The main one you need to be aware of is that modular applications use the module path, not the classpath we know and love.

The OpenJFX Getting Started Documentation walks through creating an application like this (follow the menu items "JavaFX and IntelliJ" -> "Modular with Gradle").

However, the JavaFX Gradle Plugin (version 0.0.9) can’t do what’s needed if you’re using Gradle 6.7 or above (which you will be if you’ve created a Gradle application from IntelliJ IDEA 2020.3), since Gradle changed the way it builds applications that use the Java Module System. You’ll need to change your build.gradle file to look something like:

plugins {
    id 'application'
}

group 'com.example'
version '1.0-SNAPSHOT'

repositories {
    mavenCentral()
}

def javaFXPlatform = getJavaFXPlatform()
def javaFXVersion = "15.0.1"

dependencies {
    // you need a dependency for each of the JavaFX modules you're going to use
    implementation "org.openjfx:javafx-base:${javaFXVersion}:${javaFXPlatform}"
    implementation "org.openjfx:javafx-controls:${javaFXVersion}:${javaFXPlatform}"
    implementation "org.openjfx:javafx-graphics:${javaFXVersion}:${javaFXPlatform}"
}

application {
    //Java Module System module name
    mainModule.set('com.example.javafxgradle')
    //Your JavaFX application class
    mainClass.set('com.example.javafxgradle.HelloFX')
}

java {
    // this enables Java Modularity in Gradle (version 6.7 and above)
    modularity.inferModulePath.set(true)
}

// Based on this StackOverflow answer: https://stackoverflow.com/a/65209664/653519 
private static String getJavaFXPlatform() {
    def currentOS = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
    if (currentOS.isWindows()) {
        return 'win'
    } else if (currentOS.isLinux()) {
        return 'linux'
    } else if (currentOS.isMacOsX()) {
        return 'mac'
    }
    return null
}

This application runs from the command line (or IntelliJ IDEA terminal window) with:

/.gradlew run

(You will need a JAVA_HOME that points to at least JDK 11)

It runs from the Gradle tool window via the application -> run Task

We can run it from the HelloFX.java file, either from the green arrows in the gutter, or via ⌃⇧R (MacOS) or Ctrl+Shift+F10 (Windows).

I used Java 15 as the project SDK. However, it should also run with JDK 11 or higher.

If you’re not familiar with the Java Module System, you may not want to use it in your JavaFX application. If that’s the case, read on as there are some caveats and workarounds you need to be aware of.

Without Modules

Example application code here.

The simplest Gradle approach should be to use Gradle without the Java Module System.

Follow the steps in the OpenJFX Getting Started Documentation (navigate to the link that says "Non-modular with Gradle" under "JavaFX and IntelliJ IDEA"), or clone/download the sample application code. Note that if you are not using the Java Module System, the JavaFX Gradle plugin does everything you need regardless of the version of Gradle that you’re using, so your build.gradle file is simpler than the version shown above.

Like the modular version, you can run this JavaFX application from the command line with:

/.gradlew run

Or you can run the run task via the Gradle tool window as shown above. Or you can use "Run anything" (Ctrl Ctrl) and type gradle run.

Note
Be aware that it might not work if you run the HelloFX.java file from inside the IntelliJ IDEA editor.

It’s not a showstopper, because you can still use the other methods, and running the Gradle command via IntelliJ IDEA still adds it as a valid run configuration.

JavaFX with Maven

Example application code here

The simplest way to get a working JavaFX application that uses Maven is the JavaFX Maven Archetype. Using the OpenJFX Getting Started Documentation, follow the instructions under "JavaFX and IntelliJ" -> "Modular with Maven" (or "Non-modular with Maven", at the time of writing these seem to both end up with the same result).

The nice thing about using archetypes is that all the basic code is generated for you and you don’t have to do anything. You should end up with a project like my javafx-maven-via-archetype code.

The generated application uses the Java Module System introduced in Java 9. This should be fine for a simple application, but it’s worth being aware of it in case you run into any unexpected behaviour.

This application runs from the command line (or IntelliJ IDEA terminal window) with:

mvn clean javafx:run

(This assumes you have Maven installed)

You can also run it from the green arrows in the gutter of App.java.

You will need to use Java 15 if you want to run my example application, I’ve specifically set that as the JDK in Maven.

Note
It may not work running via Maven’s tool window.

If your Operating System’s JAVA_HOME is lower than Java 15 (for example, mine’s set to Java 11), you’ll get an error trying to run javafx:run from the tool window:

It may say something along the lines of "Unsupported major.minor version". This is an issue mentioned in the OpenJFX Getting Started Documentation.

This is not a showstopper, the application will still run correctly from both the command line and from the editor.

Without Modules

Not everyone wants or needs to use the Java Module System with their applications (although I recommend people give it a try). If this is the case, you can go ahead and create the app as above, but remove the module-info.java file. In pom.xml, remove the module name from mainClass. For example, change this:

<mainClass>com.mechanitis.demo.javafxmaven/com.mechanitis.demo.javafxmaven.App</mainClass>

to this:

<mainClass>com.mechanitis.demo.javafxmaven.App</mainClass>

(See the without-modules branch in the example application).

Note
If you use the no-modules approach, you can still run the application from the command line as before, but you will not be able to run it via the editor, i.e. you won’t be able to run App.java either from the green arrows in the gutter, or via ⌃⇧R (MacOS) or Ctrl+Shift+F10 (Windows).

Final Maven Note
The IntelliJ IDEA Reactive Spring Boot tutorial, which has a JavaFX front end, uses Maven. I’ve upgraded it to use Java 15 and JavaFX 15.0.1, it does not use Java modularity, and it seems to work correctly – both running from the command line and running the UI application class from IntelliJ IDEA.

I haven’t got to the bottom of why that is, my hypothesis is because Spring is taking care of lots of the dependencies. Feel free to dig around the code.

Summary

Creating JavaFX applications is just like using any other framework – having an understanding of how to get started, and what the pros and cons of various approaches are, is key to success. JavaFX has been through exciting times over the last five years or so, and it’s nice to see we can use Java on the front end as well as for an application’s back end.

If you’re using a JavaFX front end for your application, you can build and run it in IntelliJ IDEA if it’s correctly configured in your selected build tool.

image description