How to Create a Project With JavaFX on JDK 11
There were a variety of mixed feelings towards the decoupling of JavaFX from JDK 11. Check out this post to learn how to create a project with JavaFX on JDK11.
Join the DZone community and get the full member experience.
Join For FreeThere was a mixture of feelings about the decoupling of JavaFX from JDK after its 11th release. Many of us felt that 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 better. 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, I will also be using 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 two modules. One module is logic, and the other one is gui, which JavaFX-related code belongs to.
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"
This is the content of the 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 will look like 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"
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 the 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;
}
Final 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:
javafx11-demo
│ 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 trial and error, I didn't come up with a solution to enter a piece of the Maven command to run the project, So I will do it the 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 hand. If anyone knows a better way of doing this, I would appreciate you letting me know in the comments below. 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 find 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 questions, please do not hesitate to ask — I will try my best to answer them in the comments below.
Finally, Hello World!
Published at DZone with permission of Hossein Rimaz. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments