JavaFX on JDK 11
There was a mixture of feelings about the decoupling of JavaFX from JDK after its 11th release. Many of us felt that now this is the time to say goodbye to JavaFX and switch to another GUI technology, While some others were happy about this circumstance. They believed that decoupling JavaFX from the hands of the Oracle and pursuing its development as an open-source community-driven project is a fantastic opportunity for JavaFX to get even greater. I belong to the latter group. Although I might be worried about the way that JavaFX is going to evolve, I firmly believe with the features that Java Modularity and JPMS brought to us, having a separate JavaFX module is actually fascinating. You can just include that module into your project, create a custom runtime image using the “jlink” tool and BOOM! You just have a fancy modularized project that you can easily ship and run elsewhere.
You might ask yourself, “How?”. This is basically what I am going to illustrate in this article for you. I am going to show you how you can create a modularized project with Maven.
Environment:
I am using the JDK 11 on Early Access. You can download it from this link: http://jdk.java.net/11/
$ java --version java 11-ea 2018-09-25 Java(TM) SE Runtime Environment 18.9 (build 11-ea+24) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11-ea+24, mixed mode)
And Apache Maven
$ mvn --version Apache Maven 3.5.4 (1edded0938998edf8bf061f1ceb3cfdeccf443fe; 2018-06-17T23:03:14+04:30) Maven home: C:\Program Files\Maven\apache-maven-3.5.4 Java version: 11-ea, vendor: Oracle Corporation, runtime: C:\Program Files\Java\jdk-11 Default locale: en_US, platform encoding: Cp1252 OS name: "windows 10", version: "10.0", arch: "amd64", family: "windows"
Creating a Project:
My project has 2 modules. One module is logic and the other one is gui that JavaFX related code belongs to it.
Here is the project structure:
javafx11-demo │ pom.xml │ ├───gui │ │ pom.xml │ │ │ └───src │ └───main │ └───java │ │ module-info.java │ │ │ └───com │ └───mhrimaz │ └───gui │ GUIMain.java │ └───logic │ pom.xml │ └───src └───main └───java │ module-info.java │ └───com └───mhrimaz └───logic CoolLogic.java
Configuring the “pom.xml”s:
This is the content of root pom.xml:
<?xml version="1.0" encoding="UTF-8"?> <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>com.mhrimaz</groupId> <artifactId>javafx11-demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>pom</packaging> <modules> <module>logic</module> <module>gui</module> </modules> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.7.0</version> <configuration> <source>11</source> <target>11</target> <showWarnings>true</showWarnings> <showDeprecation>true</showDeprecation> </configuration> <dependencies> <dependency> <groupId>org.ow2.asm</groupId> <artifactId>asm</artifactId> <version>6.2</version> </dependency> </dependencies> </plugin> </plugins> </build> </project>
Basically, I’m configuring the maven compiler plugin and configuring it for Java 11. Notice that I defined two modules: logic and gui.
For the logic module, pom.xml is as the following:
<?xml version="1.0" encoding="UTF-8"?> <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> <parent> <groupId>com.mhrimaz</groupId> <artifactId>javafx11-demo</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>logic</artifactId> <version>1.0-SNAPSHOT</version> </project>
Finally, for the gui module we define its pom.xml as the following:
<?xml version="1.0" encoding="UTF-8"?> <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> <parent> <groupId>com.mhrimaz</groupId> <artifactId>javafx11-demo</artifactId> <version>1.0-SNAPSHOT</version> </parent> <artifactId>gui</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>com.mhrimaz</groupId> <artifactId>logic</artifactId> <version>${project.version}</version> </dependency> <dependency> <groupId>org.openjfx</groupId> <artifactId>javafx-controls</artifactId> <version>11-ea+19</version> </dependency> </dependencies> </project>
Notice that here we have two dependencies, One is the dependency on our logic module, because every gui needs a logic, and the other one is the dependency on javafx-controls module.
Configuring the “module-info.java”s:
If you are not familiar with java modularity concepts I suggest you read my other article about JPMS and modularity.
We should export our “com.mhrimaz.logic” package in order to make it accessible outside our module.
module logic{ exports com.mhrimaz.logic; }
For the gui module, we should do several things, First of all, we should require the logic module. Another thing is that we should require javafx.controls module. And finally, we should open the “com.mhrimaz.gui” package for runtime deep-reflection access for the sake of JavaFX. We will end up to the following configuration:
module gui{ requires logic; requires javafx.controls; opens com.mhrimaz.gui to javafx.graphics; }
Last Steps:
In order to compile and build the modules enter this command:
mvn clean install
This will compile and build the modules for you. You will have this hierarchy at the end:
C:. │ pom.xml │ ├───gui │ │ pom.xml │ │ │ ├───src │ │ └───main │ │ └───java │ │ │ module-info.java │ │ │ │ │ └───com │ │ └───mhrimaz │ │ └───gui │ │ GUIMain.java │ │ │ └───target │ │ gui-1.0-SNAPSHOT.jar │ │ │ ├───classes │ │ │ module-info.class │ │ │ │ │ └───com │ │ └───mhrimaz │ │ └───gui │ │ GUIMain.class │ │ │ ├───generated-sources │ │ └───annotations │ ├───maven-archiver │ │ pom.properties │ │ │ └───maven-status │ └───maven-compiler-plugin │ └───compile │ └───default-compile │ createdFiles.lst │ inputFiles.lst │ └───logic │ pom.xml │ ├───src │ └───main │ └───java │ │ module-info.java │ │ │ └───com │ └───mhrimaz │ └───logic │ CoolLogic.java │ └───target │ logic-1.0-SNAPSHOT.jar │ ├───classes │ │ module-info.class │ │ │ └───com │ └───mhrimaz │ └───logic │ CoolLogic.class │ ├───generated-sources │ └───annotations ├───maven-archiver │ pom.properties │ └───maven-status └───maven-compiler-plugin └───compile └───default-compile createdFiles.lst inputFiles.lst
Now how to run? After a lot of searches and digging up, I didn’t come up with a solution to enter a piece of maven command to run the project, So I will do it in an old-fashioned way.
The basic command is the following:
java --module-path <all-of-your-modules-jar-file> -m <which-module>/<and-which-class-of-it-you-want-to-run>
So we are going to do it by our hand, I KNOW, IT DOESN’T SUPPOSED TO BE IN THIS WAY, but keep your expectations low my friend. If anyone knows a better way of doing this I would be appreciated to let me know it. The command is:
java --module-path gui\target\gui-1.0-SNAPSHOT.jar;logic\target\logic-1.0-SNAPSHOT.jar -m gui/com.mhrimaz.gui.GUIMain
It’s obvious that if you run this you will end up seeing this error:
Error occurred during initialization of boot layer java.lang.module.FindException: Module javafx.controls not found, required by gui
Basically, It says that during the module resolution, it didn’t found the javafx.controls module. It’s simple, you should add all the JavaFX modules to the module path. The final command is the following:
java --module-path gui\target\gui-1.0-SNAPSHOT.jar;logic\target\logic-1.0-SNAPSHOT.jar;"C:\Users\YOURUSERNAME\.m2\repository\org\openjfx\javafx-base\11-ea+19\javafx-base-11-ea+19-win.jar";"C:\Users\YOURUSERNAME\.m2\repository\org\openjfx\javafx-graphics\11-ea+19\javafx-graphics-11-ea+19-win.jar";"C:\Users\YOURUSERNAME\.m2\repository\org\openjfx\javafx-controls\11-ea+19\javafx-controls-11-ea+19-win.jar" -m gui/com.mhrimaz.gui.GUIMain
This command works perfectly fine on my windows machine. If you want the code you can find it on my GitHub.
If you have any question please do not hesitate to ask, I will try my best to answer them.
Finally, Hello World!
Published on Java Code Geeks with permission by Mohammad Rimaz, partner at our JCG program. See the original article here: JavaFX on JDK 11 Opinions expressed by Java Code Geeks contributors are their own. |
If I remember right, wasn’t JavaFX available but separate (i.e. decoupled) in Java 7, then they packaged together in Java 8? It feels as if they’re going back and forth here.
That’s Oracle to you.
“It feels as if they’re going back and forth here.”
They are, politically, but not, technically.
It was hard to get people to code to JavaFX in 7 because it wasn’t “just part of the JDK”.
My hope is that this political hurdle can be overcome by the technical advantages of how things are architectured now, so that the end-user doesn’t notice anything wrong, an app that they run with JavaFX will always just run, and not error out, because JavaFX wasn’t bundled in with Java, that they have on their computer already.
I can’t see how this will work reliably in the longer term. I have been trying for the last 5 hours to sort this out for both my Java8-JavaFx and Kotlin-JavaFx programs under Linux Mint 19. I am just about to give up and go back to using Oracle JDK 10 permanently. I like to use the command line to have control, but with having to specify the modules then the classes in the modules, it becomes a command paragraph not a command line. Then for every future change it will mean going through all my applications builds changing all… Read more »