<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Luca Guadagnini</title>
    <description>The latest articles on DEV Community by Luca Guadagnini (@lucaguada).</description>
    <link>https://dev.to/lucaguada</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F20949%2Fed0654e4-19a8-4ab7-92d7-06cb9c35d33c.jpg</url>
      <title>DEV Community: Luca Guadagnini</title>
      <link>https://dev.to/lucaguada</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lucaguada"/>
    <language>en</language>
    <item>
      <title>JavaFX, JLink and JPackage</title>
      <dc:creator>Luca Guadagnini</dc:creator>
      <pubDate>Thu, 25 Mar 2021 16:57:25 +0000</pubDate>
      <link>https://dev.to/cherrychain/javafx-jlink-and-jpackage-h9</link>
      <guid>https://dev.to/cherrychain/javafx-jlink-and-jpackage-h9</guid>
      <description>&lt;p&gt;A few days ago, for the &lt;em&gt;Java User Group Trentino-Alto Adige-Südtirol&lt;/em&gt; I shown some experiments on &lt;strong&gt;JavaFx&lt;/strong&gt;, &lt;strong&gt;JLink&lt;/strong&gt; and &lt;strong&gt;JPackage&lt;/strong&gt;. The purpose of the talk was to show the chance to use JavaFX working with new JDK tools such as JLink (since OpenJDK 9) and JPackage (provided by the new OpenJDK 16) for rich client development.&lt;br&gt;
Although some may state «&lt;em&gt;JavaFX is dead&lt;/em&gt;» since it's not part of the &lt;strong&gt;OpenJDK&lt;/strong&gt; anymore, JavaFX is actually alive and kicking. &lt;strong&gt;OpenJFX&lt;/strong&gt; (aka Open JavaFX) is a side project still maintained and evolved by Oracle, Gluon, BellSoft and others. Suddenly, because of the advent of OpenJDK, Adoptium and other free OpenJDK builds, it may not be that straightforward to understand how to get started with JavaFX, especially if you still working on an Oracle Jave SE 1.8.0 distribution. Let's try to get there.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before starting
&lt;/h2&gt;

&lt;p&gt;To grasp the example, you need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Git&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Apache Maven&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Sdkman&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;a Linux shell or a Wsl2 shell for Windows (sorry I know nothing about MacOS)&lt;/li&gt;
&lt;li&gt;an editor for the pom file (even &lt;code&gt;Vim&lt;/code&gt; is fine, but I don't remember how to exit from it, so don't ask me).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;DISCLAIMER&lt;/strong&gt;&lt;br&gt;
Keep in mind that I will write regarding &lt;code&gt;module-info&lt;/code&gt; and &lt;strong&gt;Java Platform Module System&lt;/strong&gt;, but I won't explain too much about them.&lt;br&gt;
The goal of this post is not about how you have to organize a project, but how to make the tools work for you. I will instead write something more about JPMS in a future post (it is quite intriguing and intricated).&lt;/p&gt;

&lt;h2&gt;
  
  
  What is JavaFX?
&lt;/h2&gt;

&lt;p&gt;JavaFX is a framework of graphics and media packages that enables developers to create and deploy rich client applications.&lt;/p&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;Let's take a basic JavaFX example, for instance, this one:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://gitlab.com/lucaguada/treefx" rel="noopener noreferrer"&gt;https://gitlab.com/lucaguada/treefx&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The source code is pretty old and is a JavaFX 2.1 example taken from here: &lt;a href="https://docs.oracle.com/javafx/2/animations/basics.htm" rel="noopener noreferrer"&gt;Oracle Docs&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I configured the &lt;code&gt;pom.xml&lt;/code&gt; as simple as possible, or at least this was my intention. I just set two plugins: &lt;code&gt;maven-compiler-plugin&lt;/code&gt; to avoid compilation issues when we advance the Java version during our tests and &lt;code&gt;exec-maven-plugin&lt;/code&gt; for being able to run our application from the terminal.&lt;/p&gt;

&lt;h2&gt;
  
  
  Oracle Java SE to OpenJDK
&lt;/h2&gt;

&lt;p&gt;As I mentioned before, JavaFX is not part of the OpenJDK anymore. Let's see if such a boomer like me is correct.&lt;/p&gt;

&lt;p&gt;Download the &lt;code&gt;tar.gz&lt;/code&gt; file of Oracle Java SE 1.8.0 from here: &lt;a href="https://www.oracle.com/java/technologies/javase-downloads.html" rel="noopener noreferrer"&gt;Oracle Java&lt;/a&gt; and don't worry about the license, the FAQ explicitly states this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

Oracle Java SE8 updates, which includes the Oracle JRE with Java Web Start, continue to be free for personal use, development, testing, prototyping, demonstrating and some other important uses explained in this FAQ under the OTN License Agreement for Java SE. Personal users can continue downloading the Oracle Java SE 8 JRE at java.com.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Unzip the package in the &lt;code&gt;.sdkman/candidates/java&lt;/code&gt; folder. You should be able to check the OracleJDK by typing:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;sdk list java


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Sdkman should list the Oracle Java SE as follow:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

Unclassified  |     | 8.0.281      | none    | &lt;span class="nb"&gt;local &lt;/span&gt;only | 8.0.281-oracle


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nice! Therefore we can now compile our project:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;sdk use java 8.0.281-oracle
Using java version 8.0.281-oracle &lt;span class="k"&gt;in &lt;/span&gt;this shell.
 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile &lt;span class="nb"&gt;exec&lt;/span&gt;:java


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and if everything is fine:&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwmoh0n8legdqc5x0gkj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fdwmoh0n8legdqc5x0gkj.png" alt="TreeFX in action"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Nice twice! However, we don't want to have a headache for Oracle licenses/subscriptions/etc., so we now change the OracleJDK with an Open one and compile again.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;sdk &lt;span class="nb"&gt;install &lt;/span&gt;java 8.0.272.hs-adpt
... &lt;span class="nb"&gt;install &lt;/span&gt;process by sdkman ...
 &lt;span class="nv"&gt;$ &lt;/span&gt;sdk use java 8.0.272.hs-adpt
Using java version 8.0.272.hs-adpt &lt;span class="k"&gt;in &lt;/span&gt;this shell.
 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile &lt;span class="nb"&gt;exec&lt;/span&gt;:java


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and tragically:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Errors, errors everywhere! TreeFX can't find any package of the framework JavaFX! How to solve this? JavaFX is now a set of self-contained dependencies, so let's modify the &lt;code&gt;pom.xml&lt;/code&gt; file by defining the right dependencies.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;dependencies&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openjfx&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;javafx-controls&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;16&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openjfx&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;javafx-media&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;16&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependencies&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;and then compile again. But... again...&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project treefx: Compilation failure
[ERROR] /home/.../treefx/src/main/java/io/trydent/treefx/Flower.java:[7,20] cannot access javafx.scene.Group
[ERROR]   bad class file: /home/.../.m2/repository/org/openjfx/javafx-graphics/16/javafx-graphics-16-linux.jar(javafx/scene/Group.class)
[ERROR]     class file has wrong version 55.0, should be 52.0
[ERROR]     Please remove or make sure it appears in the correct subdirectory of the classpath.


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;No more errors about missing packages, but class file version! What does it mean? Every time the Java Compiler compiles your code, it annotates your classes with a number to identify the target JDK release. In this case, the class version 55.0 targets JDK 11, but we're using JDK 8, therefore the class version number should be at a maximum of 52.0.&lt;/p&gt;

&lt;p&gt;Unfortunately, there is no way to downgrade JavaFX to a version compatible with JDK 8. Sure, as someone already suggested to me, we can download &lt;strong&gt;Liberica OpenJDK 8 with JavaFX&lt;/strong&gt; (or the Azul one) however, we will be forever stuck to JavaFX 8. Being locked to JavaFX 8 doesn't allow us to benefit from having bug fixes and other kinds of improvements.&lt;/p&gt;

&lt;p&gt;It's time to upgrade our OpenJDK to 11.&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenJDK 11
&lt;/h2&gt;

&lt;p&gt;Once we set our JavaFX dependencies in the &lt;code&gt;pom.xml&lt;/code&gt;, we can try to switch to an OpenJDK 11:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;sdk use java 11.0.10.hs-adpt
Using java version 11.0.10.hs-adpt &lt;span class="k"&gt;in &lt;/span&gt;this shell.
 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile &lt;span class="nb"&gt;exec&lt;/span&gt;:java


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;And everything will be fine. No more errors about missing packages and class versions.&lt;/p&gt;

&lt;p&gt;Because our application is ready, we can package it into a self-executable-jar and release it to our customers/friends/pets (well, if they are all interested in Tree animations, of course). By doing so, we face an old-fashioned issue: we depend on the customer/friend/pet's installed JDK. We can't upgrade our development JDK (let's think about new API's and runtime improvements, etc.) until our customers don't upgrade their own. Yes, we could package the application with a JRE, but this would lead to having a pretty big sized ZIP for just one animation.&lt;/p&gt;

&lt;h2&gt;
  
  
  JLink, the Java Linker
&lt;/h2&gt;

&lt;p&gt;As explained in JEP 282, &lt;strong&gt;JLink&lt;/strong&gt; is a tool that can assemble modules and their dependencies into a custom Java runtime image. Since the JRE, JDK and &lt;strong&gt;some&lt;/strong&gt; libraries/frameworks are now restructured in modules, we can create a custom JRE image for our wonderful JavaFX application!&lt;/p&gt;

&lt;p&gt;JavaFX is indeed modularized, so we can try!&lt;/p&gt;

&lt;p&gt;Before starting, though, I have to inform you that I skipped the official &lt;em&gt;Maven JLink Plugin&lt;/em&gt; usage. In a draft of this article, I  explained how to work with the JLink plugin and JavaFX, but I realized it was far too long and not very useful in practice (for this example, at least). Instead of the Maven JLink Plugin, we'll use the official &lt;em&gt;JavaFX JLink Plugin&lt;/em&gt; provided by the JavaFX development team to simplify the process.&lt;/p&gt;

&lt;p&gt;Let us modify the &lt;code&gt;pom.xml&lt;/code&gt; and append a Maven plugin for &lt;strong&gt;JavaFX and JLink&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.openjfx&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;javafx-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;0.0.5&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;compress&amp;gt;&lt;/span&gt;2&lt;span class="nt"&gt;&amp;lt;/compress&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;noHeaderFiles&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/noHeaderFiles&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;stripDebug&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/stripDebug&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;noManPages&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/noManPages&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;launcher&amp;gt;&lt;/span&gt;treefx&lt;span class="nt"&gt;&amp;lt;/launcher&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;mainClass&amp;gt;&lt;/span&gt;treefx/com.acme.treefx.TreeFX&lt;span class="nt"&gt;&amp;lt;/mainClass&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;jlinkImageName&amp;gt;&lt;/span&gt;treefx&lt;span class="nt"&gt;&amp;lt;/jlinkImageName&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;jlinkZipName&amp;gt;&lt;/span&gt;treefx&lt;span class="nt"&gt;&amp;lt;/jlinkZipName&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The configuration is not quite self-explanatory, here some hints:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;compress&lt;/em&gt; enables compression of resources, we set to 2 for compressing to ZIP&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;noHeaderFiles&lt;/em&gt; excludes C header files for supporting native-code programming (we don't need that for our custom JRE) &lt;/li&gt;
&lt;li&gt;
&lt;em&gt;stripDebug&lt;/em&gt; excludes JRE debug information (yeah we don't need this too)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;noManPages&lt;/em&gt; excludes the JDK docs&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;jlinkImageName&lt;/em&gt; the runtime final name&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;jlinkZipName&lt;/em&gt; the ZIP final name&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;launcher&lt;/em&gt; the executable name&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;mainClass&lt;/em&gt; what &lt;code&gt;main&lt;/code&gt; needs to be launched by specifying module, package and class.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We set all such exclusions for shrinking our custom JRE to a smaller size than the usual one.&lt;br&gt;
However, if we try the new plugin command:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile javafx:jlink


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Something is still missing:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[ERROR] Failed to execute goal org.openjfx:javafx-maven-plugin:0.0.5:jlink (default-cli) on project treefx: Error: jlink requires a module descriptor


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;As I said before if JDK, JRE and JavaFX are now modularized, this implies that we need to modularize our application too. Create a new file named &lt;code&gt;module-info.java&lt;/code&gt; in the folder &lt;code&gt;src/main/java&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;

&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;treefx&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;javafx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;controls&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
  &lt;span class="n"&gt;requires&lt;/span&gt; &lt;span class="n"&gt;javafx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;media&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

  &lt;span class="n"&gt;opens&lt;/span&gt; &lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;acme&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;treefx&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt; &lt;span class="n"&gt;javafx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;graphics&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;The file defines our application as a module named &lt;code&gt;treefx&lt;/code&gt; and our module requires some modules as well in order to work, &lt;code&gt;javafx.controls&lt;/code&gt; and &lt;code&gt;javafx.media&lt;/code&gt;.&lt;br&gt;
I don't want to explain too much about it, but keep in mind that &lt;em&gt;modules are a new way to organize your applications and libraries and enable strong encapsulation and implementation/reflection hiding&lt;/em&gt;. Knowing this, what about that last statement &lt;code&gt;opens&lt;/code&gt; in &lt;code&gt;module-info&lt;/code&gt;?&lt;br&gt;
There are some cases where you have to enable reflection (because of modules, reflection is inaccessible by default) for your classes, because of frameworks for instance. In our case we have to enable the reflection of our package &lt;code&gt;com.acme.treefx&lt;/code&gt; to the module &lt;code&gt;javafx.graphics&lt;/code&gt; to let JavaFX work.&lt;/p&gt;

&lt;p&gt;Then once again:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile javafx:jlink


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;... finally ...&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

[INFO] Building zip: /home/.../treefx/target/treefx.zip


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Yeeeah our application is ready to be propagated to Knowhere (cit.)!&lt;/p&gt;

&lt;p&gt;Let's take a look at what actually happened in the target folder:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;tree target/treefx


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

target/treefx
├── bin
│   ├── java
│   ├── keytool
│   └── treefx
├── conf
│   ├── [...]
├── legal
│   ├── [...]
├── lib
│   ├── [...]
└── release


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;What do we have in the generated &lt;code&gt;treefx.zip&lt;/code&gt;? As we can see, it's just a JRE with our application encapsulated inside. In folder &lt;code&gt;bin&lt;/code&gt;, we can find the launcher &lt;code&gt;treefx&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;And the size of the ZIP file? Just &lt;em&gt;47Mb&lt;/em&gt;! The best part? If our application only needs the modules we declared in &lt;code&gt;module-info&lt;/code&gt;, the size will increase only if our application grows in terms of compiled classes.&lt;/p&gt;

&lt;p&gt;Nice trice, right? But we want more! For the sake of aesthetics, we prefer to distribute our application with an official &lt;code&gt;deb&lt;/code&gt; package how can we do this?&lt;/p&gt;

&lt;p&gt;It's time to upgrade our OpenJDK to 16!&lt;/p&gt;

&lt;h2&gt;
  
  
  OpenJDK 16 and JPackage
&lt;/h2&gt;

&lt;p&gt;OpenJDK 16 has been released on 16th March. However, this is not the right post to talk about all the new shining features and tools, but it is the right post to talk about a new particular tool: &lt;strong&gt;JPackage&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;JPackage was introduced as an incubating tool from JDK 14 to JDK 15 and is now production-ready for packaging self-contained Java applications.&lt;/p&gt;

&lt;p&gt;As above we want to rely on Maven and fortunately, we got a well-packed plugin (&lt;a href="https://github.com/petr-panteleyev/jpackage-maven-plugin" rel="noopener noreferrer"&gt;JPackage Plugin&lt;/a&gt;)  on Maven Central that we can add:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;

&lt;span class="nt"&gt;&amp;lt;plugin&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.panteleyev&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jpackage-maven-plugin&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;1.4.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;configuration&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;name&amp;gt;&lt;/span&gt;TreeFX&lt;span class="nt"&gt;&amp;lt;/name&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;appVersion&amp;gt;&lt;/span&gt;1.0.0&lt;span class="nt"&gt;&amp;lt;/appVersion&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;vendor&amp;gt;&lt;/span&gt;com.acme&lt;span class="nt"&gt;&amp;lt;/vendor&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;destination&amp;gt;&lt;/span&gt;target/dist&lt;span class="nt"&gt;&amp;lt;/destination&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;module&amp;gt;&lt;/span&gt;treefx/com.acme.treefx.TreeFX&lt;span class="nt"&gt;&amp;lt;/module&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;runtimeImage&amp;gt;&lt;/span&gt;target/treefx&lt;span class="nt"&gt;&amp;lt;/runtimeImage&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;linuxShortcut&amp;gt;&lt;/span&gt;true&lt;span class="nt"&gt;&amp;lt;/linuxShortcut&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;linuxPackageName&amp;gt;&lt;/span&gt;treefx&lt;span class="nt"&gt;&amp;lt;/linuxPackageName&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;linuxAppCategory&amp;gt;&lt;/span&gt;Utilities&lt;span class="nt"&gt;&amp;lt;/linuxAppCategory&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;linuxMenuGroup&amp;gt;&lt;/span&gt;Utilities&lt;span class="nt"&gt;&amp;lt;/linuxMenuGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;icon&amp;gt;&lt;/span&gt;${project.basedir}/duke.png&lt;span class="nt"&gt;&amp;lt;/icon&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;javaOptions&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;option&amp;gt;&lt;/span&gt;-Dfile.encoding=UTF-8&lt;span class="nt"&gt;&amp;lt;/option&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/javaOptions&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/configuration&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/plugin&amp;gt;&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;I have to spend some words about the configuration because it's a little bit tricky on some points.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Easy part&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;name&lt;/em&gt; sets the application name (you don't say!)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;appVersion&lt;/em&gt; as any other application, our TreeFX has a release version too!&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;vendor&lt;/em&gt; sets the vendor or our Acme company&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;destination&lt;/em&gt; sets the destination folder for the generated package&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Tricky part&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;module&lt;/em&gt; we set the module and the main class of our application since JPackage will generate a new executable for our package&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;runtimeImage&lt;/em&gt; is usually set to our development OpenJDK, because JPackge could work with JLink to create the custom JRE, but because of some issues I found with JavaFX and JLink (the process is not straightforward), we trick JPackage and we tell it to take the previous custom JRE created with the OpenJFX plugin&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Linux part&lt;/strong&gt; (I put it just for the sake of completeness)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;linuxShortcut&lt;/em&gt; creates a shortcut after the application installation process&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;linuxPackageName&lt;/em&gt; sets the final &lt;code&gt;deb&lt;/code&gt; package name&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;linuxAppCategory&lt;/em&gt; sets the Linux application category&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;linuxMenuGroup&lt;/em&gt; sets the Linux menu-group&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Maybe I have to spend more words on the &lt;em&gt;tricky part&lt;/em&gt;. As mentioned above, JPackage is a tool for packaging a self-contained Java application, &lt;strong&gt;any&lt;/strong&gt; kind of Java application, modularized and non-modularized applications. But for this example, we want to distribute a simple animation and it would be quite weird to distribute a whole JRE image for the sake of one animation. Therefore, always think about what you really need for &lt;em&gt;your&lt;/em&gt; application and let the right tool works for you.&lt;/p&gt;

&lt;p&gt;About &lt;em&gt;linux part&lt;/em&gt;. JPackage allows you to package not only for Linux, but also for Windows and MacOS. However, JPackage depends on the operating system in order to work, so you can't package a Linux app, if you're using Window or MacOS, in a nutshell, no, cross-compiling is not an option. We will try to package our TreeFX app for Windows in an addendum to this article (maybe next week).&lt;/p&gt;

&lt;p&gt;Enough chatting. Let's see it work:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;mvn clean compile javafx:jlink jpackage:jpackage


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Wait a while and then:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;target/dist/
treefx_1.0.0-1_amd64.deb


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Nice fourice! We now have our package for AMD64 arch (yeah that's mine). If we still have some curiosity about how the &lt;code&gt;deb&lt;/code&gt; package is organized, we can unpack it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;

 &lt;span class="nv"&gt;$ &lt;/span&gt;dpkg-deb &lt;span class="nt"&gt;-R&lt;/span&gt; target/dist/treefx_1.0.0-1_amd64.deb target/unpacked
 &lt;span class="nv"&gt;$ &lt;/span&gt;tree target/unpacked


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

target/unpacked
├── DEBIAN
│   ├── control
│   ├── postinst
│   ├── postrm
│   ├── preinst
│   └── prerm
└── opt
    └── treefx
        ├── bin
        │   └── TreeFX
        ├── lib
        │   ├── app
        │   │   └── TreeFX.cfg
        │   ├── runtime
        │   │   ├── [...]
        │   ├── TreeFX.png
        │   └── treefx-TreeFX.desktop
        └── share
            └── doc
                └── copyright


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We could optimize things and surf into other JPackage configurations, but so far so good (as an old Bryan Adams' album and song said).&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusions
&lt;/h2&gt;

&lt;p&gt;We finally reached the bottom of this tutorial, a lot more could be said about JPMS, JLink and JPackage, this is indeed an introduction to tickle your curiosity, and as you can see we can still build nice stuff with JavaFX and Java technology.&lt;/p&gt;

&lt;p&gt;Dig into &lt;a href="https://gitlab.com/lucaguada/treefx" rel="noopener noreferrer"&gt;https://gitlab.com/lucaguada/treefx&lt;/a&gt; repository and look at the different branches to have a clearer vision of the above steps.&lt;/p&gt;

&lt;p&gt;See you, space cowboy!&lt;/p&gt;

&lt;p&gt;«A chance to begin again in a golden land of opportunity and adventure!»&lt;/p&gt;

</description>
      <category>java</category>
      <category>javafx</category>
      <category>jlink</category>
      <category>jpackage</category>
    </item>
    <item>
      <title>Let's introduce ourselves</title>
      <dc:creator>Luca Guadagnini</dc:creator>
      <pubDate>Sun, 21 Mar 2021 20:01:50 +0000</pubDate>
      <link>https://dev.to/lucaguada/let-s-introduce-ourselves-h1k</link>
      <guid>https://dev.to/lucaguada/let-s-introduce-ourselves-h1k</guid>
      <description>&lt;p&gt;Hi there all!&lt;/p&gt;

&lt;p&gt;I'm Luca from a not that big city in the north of Italy, Trento. I'm an ordinary computer scientist loving work with &lt;strong&gt;Java&lt;/strong&gt; and dig into &lt;em&gt;object-oriented concepts&lt;/em&gt; (such as object thinking), patterns and principles about &lt;em&gt;Domain-Driven Design&lt;/em&gt;. My experience as a developer started during Commodore 64 days when I recorded my first personal diary application on a tape (good times!) with Basic. Then I had to learn other technologies and programming languages at High School, University and job.&lt;br&gt;
However, when I have to learn design principles and patterns, I always choose Java because of three aspects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;Philosophy&lt;/em&gt;, Java is traditionalist, takes time to have some language syntax upgrade because of retro-compatibility, but frankly? I don't care. I am always able to do anything I need with it;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Nostalgia&lt;/em&gt;, Java was my programming language during my Univerisity days, since Merlin (codename for version 1.4.0) and when I'm coding with it, I feel like I'm in one of the best days of my life;&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;History&lt;/em&gt;, how Java changed OOP; the rise and fall of Sun Microsystems; Oracle vs. Google; the paper about «generics» written by Odersky; OpenJDK; etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I could say other things about Java, OpenJDK, object-oriented paradigm, history and so on, but I prefer to let the blog speak for me with my posts (if I can keep a pace).&lt;/p&gt;

&lt;p&gt;Oh, wait! As you can see on the top, I will always put a movie reference to these three: &lt;strong&gt;Blade Runner&lt;/strong&gt;, &lt;strong&gt;Excalibur&lt;/strong&gt; and &lt;strong&gt;Clash of the Titans&lt;/strong&gt; (because I like reading sci-fi, Arthurian cycle and most of all, mythology).&lt;/p&gt;

&lt;p&gt;See you next time!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Be2iveQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9foogq87dvcegodv3ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Be2iveQU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m9foogq87dvcegodv3ag.png" alt="Duke tumbles"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>java</category>
      <category>ddd</category>
      <category>oop</category>
    </item>
  </channel>
</rss>
