Desktop Java

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.

javafx

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!

javafx

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.

Mohammad Rimaz

Hossein currently is Software Engineering Student at K.N. Toosi University of Technology and a junior developer. He is a passionate Java programmer, especially interested in GUI programming with JavaFX. His interest includes Big Data, Data Visualization, and Recommender Systems
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

4 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
JoeHx
5 years ago

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.

Cergey Chaulin
Cergey Chaulin
5 years ago
Reply to  JoeHx

That’s Oracle to you.

Roman Coder
Roman Coder
5 years ago
Reply to  JoeHx

“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.

Ray54
Ray54
5 years ago
Reply to  JoeHx

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 »

Back to top button