bliako
bliako

Reputation: 1133

Java Runtime Environment (JRE) with module support?

In searching for a JRE to run my (javafx-based) desktop application I found JRE version 8 from here https://www.java.com/en/download/manual.jsp . This is the default, and this is where I am redirected when clicking the JRE link on Oracle's website (https://www.oracle.com/downloads/#category-java)

But, the JRE does not support --module-path obviously because it's too old.

What are my options for running my app on non-developer machines? (note the JRE is 60MB and the JDK is 190MB).

I am afraid to ask why the default JRE download is too old?

My app compiles with openjdk 17.0.9 2023-10-17

Upvotes: 1

Views: 950

Answers (3)

DuncG
DuncG

Reputation: 15196

You should try using jlink to make a compatible JRE from a JDK. Before using jlink, verify that the JDK you want to base the JRE on can run your application using appropriate class-path / module-path entries.

If that works, try to generate a JRE that just contains the modules you use such as JavaFX. For example:

set JAVAFX_MODS=C:\java\javafx-jmods-21
jlink --module-path "%JAVAFX_MODS%" --add-modules javafx.base,javafx.controls,javafx.graphics --strip-debug --no-man-pages --no-header-files --output jre-fx

This means that you can use jre-fx\bin\java to launch any class that uses JavaFX without specifying JavaFX modules again.

Later, you could also use jlink to make a JRE with your own module, if you have correct dependences on JavaFX and set the module-path, the new JRE will contain everything needed to run your application:

jlink --module-path "%JAVAFX_MODS%;your-module-dir" --add-modules yourmodule --strip-debug --no-man-pages --no-header-files --output jre-all

With this new JRE - jre-all\bin\java - you only need to specific the launch class names, all modules are included.

If you need to distribute your application for other machines then look at jpackage to build installers - EXE/MSI on Windows or other packager for Mac/Linux. It can be setup to use your pre-generated JRE with jpackage --runtime-image jre-all or it can use jlink internally for you each time it is launched.

Upvotes: 2

bliako
bliako

Reputation: 1133

The answer by @BasilBourque lists the options for downloading JRE which supports latest java features and understand the --add-modules features. This is the accepted answer to my question.

However, I will outline here the whole process of packaging my app and its dependencies because, for my case, jlink kept complaining that it did not find basic dependencies, see comments under @DuncG 's answer.

I have also placed a demo at https://github.com/hadjiprocopis/javafx-uberjar

  1. Create CLASSPATH, MODULEPATH and MODULES for your app. If you are using maven this is easy by parsing the output of mvn -X javafx:run@dry-run-cli to create said vars.

  2. Collect the dependencies (jars) somehow. To me, it does not sound logical to download all these dependencies when I have maven which downloaded already these in its repository (located at ~/.m2/repository/...). So, I resorted to the spring-boot maven plugin which creates a JAR with all dependencies plus my app classes. This JAR warns with WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module ...' and I did not trust it to distribute it. In any event, this jar file now contains all the dependent jars in its lib/*. As a bonus it can contain OS-specific javafx jars for any other OSes you specify in the pom.xml as a <dependency> with <classifier> set to linux,win,mac, etc.

  3. The structure of the distribution zip/tar-ball will be: a. lib dir to contain all 3rd-party jar dependencies, even module jars, even OS-specific jars e.g. javafx-media-22-ea+11-mac.jar, javafx-media-22-ea+11-win.jar, etc. b. classes dir to contain your apps classes or a jar. c. launchers dir to contain launcher scripts for your target OS(es).

  4. The launcher script will in general be something like: java -classpath "classes:lib/xyz.jar:..." --module-path "lib/javafx...jar:lib/..." --add-modules "javafx.base,..." com.myapp.Main Note that in M$ the classpath separator ':' should be ';'

Now the last and biggest problem is to find a JRE which provides a java command which understands --module-path et.al. (which were introduced with java v9+). What prompted me to ask this question was the fact that oracle provides a JRE (via www.java.com) which supports java version 8!!!!! (When currently on java version 20 and counting). The oracle obviously knows all, so I will not dispute this decision. The fact is, that I am jreless after all this hard work.

All people answering this question (thank you all for your effort) suggested to create my own JRE using jlink. That did not work for me. It complains that it does not find basic dependency like java.base (using openJDK v17 on Linux Fedora installed via its package manager from package java-17-openjdk-devel : OpenJDK 17 Development Environment). In addition, the lame example hellofx assumes that my app is a module, which it isn't. Additionally, maven javafx:jlink fails as well (for me) with various dependencies not found. It is a mystery because maven compile javafx:run runs without problems.

Since creating my own JRE is not working for me, I resorted to downloading a JRE supplied by https://adoptium.net/en-GB/temurin/releases/ (I think it is associated with Eclipse). Is it safe? Is it "official"? I have no idea.

The answer by @Basil Bourque lists a few more options. (And actually is the accepted answer)

I have placed a demo at https://github.com/hadjiprocopis/javafx-uberjar

it runs on linux and can create a distribution zip archive for linux, mac and/or the unnamed-os.

It relies on your app being developed as a maven project because all the dependencies are collected via maven and spring-boot plugin. All the javafx depdendencies will be read from the local maven repository it uses for compiling and running your app. There is no need for you to download any third-party dependencies and keep parallel versions!

thanks for the help (but no thanks :))

Upvotes: 1

Basil Bourque
Basil Bourque

Reputation: 340070

tl;dr

Two vendors provide editions of their JDK/JRE products for Java 17, 21, and current 22 bundled with the modern generation of OpenJFX libraries implementing JavaFX: Azul Systems and BellSoft.

Details

Understand that JavaFX has never been a standard part of Java.

And understand that JavaFX is now implemented in the open-source project OpenJFX. That project is under continual active development, co-led by Oracle Corp and the Gluon company.

Years ago, Oracle chose to bundle JavaFX libraries with some of its JDK/JRE products. Then later they stopped bundling.

Oracle is but one of several vendors offering JDK/JRE products. See Java Is Still Free for an explanation of the Java ecosystem.

Some JDK/JRE vendors currently choose to bundle the JavaFX libraries implemented as OpenJFX in some editions of their products. I know of at least two such vendors:

The Java Platform Module System arrived in 2017 in Java 9 and later. The vendors listed above offer JavaFX-bundles for the modularized LTS versions 11, 17, and 21, as well as the current version (now 22).

JavaFX 22 requires JDK/JRE 17 or later.

Alternatively, you can bundle the OpenJFX libraries within your app. And you can bundle a JRE within your app, and optionally slim down the JRE to include only the parts that your app uses. The OpenJDK project offers tooling to assist: jlink and jpackage.

The cutting-edge technology uses GraalVM to produce a native app from your JavaFX project.


You asked:

But, the JRE does not support --module-path obviously because it's too old.

Java 9 and later has the Java Platform Module System (JPMS). Focus on the LTS versions (11, 17, 21) and current (22) as the other versions have reached EOL(End of Life). The latest versions of OpenJFX support Java 17 and later.

What are my options for running my app on non-developer machines?

If you have control over user machines, such as in an enterprise or education environment, consider having the sysadmins install a JRE that comes bundled with the necessary OpenJFX libraries.

In a niche market, perhaps you can require your users to install a JRE bundled with the OpenJFX libraries.

In a broad retail market, you’ll need to bundle both a JVM and the OpenJFX libraries within your app. The app marketplaces such as Apple App Store will accept such a product.

(note the JRE is 60MB and the JDK is 190MB).

You can greatly reduce that size by using the jlink tool with your JPMS modularized project.

I am afraid to ask why the default JRE download is too old?

The “why” is simply that Oracle later decided to stop bundling JavaFX libraries with their own JDK/JRE products.

But you are free to bundle the OpenJFX libraries within your app, at no cost.

And, you have the choice of obtaining more recent versions of Java JDK/JRE bundled with OpenJFX libraries from vendors other than Oracle. You can obtain free-of-cost products as well as products with paid support.

My app compiles with openjdk 17.0.9 2023-10-17

Then you can use OpenJFX 22 while compiling for Java 17.

Upvotes: 10

Related Questions