IntelliJ IDEA
IntelliJ IDEA – the Leading Java and Kotlin IDE, by JetBrains
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
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
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.