We want to use both SWT and JavaFX in an Eclipse plugin within our RCP application. Unfortunately, we're experiencing problems integrating SWT with JavaFX under Java 11. The build environment uses e(fx)clipse 3.5. We're developing against the Community edition of Azul Systems' "Zulu" JDK 11, bundled with Azul's version of OpenJFX.
Formerly, we developed under Java 8. At that point, our build used a compile-time class path referring to jfxswt.jar, which lived in the jre/lib directory of the JDK. We didn't use any special class path settings at run-time.
We are now trying to move to Java 11. There, this JAR has become javafx-swt.jar and lives in the lib directory of the JDK. It no longer seems to be enough to set the class path to refer to this JAR at compile time: it seems to be necessary to do so at run time too. If we don't do this, we get an error (java.lang.NoClassDefFoundError: javafx/embed/swt/FXCanvas).
As a test, we experimentally embedded javafx-swt.jar within the JAR implementing our Eclipse plugin. We then referred to it in that plugin's .classpath file, and the code worked as expected. Unfortunately, we can't embed the JAR this way for legal and other reasons.
A note on Java modules: javafx.swt does not show up in the output when we issue the --list-module command. We tried running the application using parameters -p /path/to/JDK/lib/javafx-swt.jar --add-modules javafx.swt, but this doesn't seem to solve the problem.
My question: Is there a way to set up the class or module path to allow our Eclipse plugin to find this library in the JRE? Any solution would have to work with whatever JRE the code happens to be run against (I think it is all right to assume lib/javafx-swt.jar will live in that JRE).
Would it help to use a separately-downloaded version of OpenJFX rather than the copy of OpenJFX in our JDK?
Very many thanks ☺
Related
I tried installing javaFX on my eclipse and it worked fine at first. Then I decided I want to make a specific JRE to save me from doing all the extra steps (adding user library each time, etc..) and I think I followed the tutorial well but now the programs won't run and I get this message from the JVM launcher:
(Error:--add-- modules requires modules to be specified)
note: the compilation works fine but after running it that happens
I'm not very experienced with these types of things and I have no idea what I did wrong so please ask me for any necessary details
any suggestions?
Information on VM arguments for adding modules is in the documentation:
Eclipse: non-modular from the IDE
Add VM arguments
To solve the issue, click on
Run ->
Run Configurations... ->
Java Application
create a new launch configuration for your project named hellofx and
add these VM arguments:
--module-path "\path\to\javafx-sdk-19\lib" --add-modules javafx.controls,javafx.fxml
This should be done if the JDK or JRE you are using does not include the JavaFX modules in its base module layer (which applies to most common JDK or JRE distributions) and you are executing your application via the IDE (e.g. not via maven with the javafx-maven-plugin).
FAQ
Then I decided I want to make a specific JRE to save me from doing all the extra steps
You don't need to build your own JRE with JavaFX modules.
You can use a pre-built JRE (or JDK) that includes JavaFX:
Azul Zulu JDK FX 19 Win x86 64 bit OR
Liberica "Full JDK"
With either of those, the JavaFX modules are included in the base JDK. That means you don't specify JavaFX libraries in build tool dependencies, or manually in the IDE, and you don't need compile or VM arguments for JavaFX modules.
I've created a small HelloWorld Java app that relies on OpenJDK 11 and JavaFX. The app is packaged in a jar file which can only be run if I have installed Java 11 and JavaFX on my system separately.
Now I'd like to convert my jar into a self-contained Java application which includes JavaFX and a fully-functional Java runtime environment. This will allow me to run my app without installing OpenJDK 11 (which presents technical hurdles such as setting PATH correctly etc).
I can find information about creating self-contained Java applications on Java 10 but I cannot find information about bundling a Java app with OpenJDK 11 and JavaFX.
How can I ship a self-contained Java app (which includes a java runtime) with OpenJDK 11 and JavaFX?
Modular Java, jlink, & jpackage
Follow these tutorials found at the new home for JavaFX after having been spun out of Oracle to Gluon.
You will need to write code using modular Java. Add JavaFX 11 as a dependency to your project. And use the new linking/packaging tools to bundle a subset of the JDK within your app.
Learn about:
Java Platform Module System
jlink (JEP 282)
jpackage (JEP 343)
No more JRE
Oracle no longer intends for end-users to be installing a JRE or a JDK. Java Applets in a browser and Java Web Start app delivery are both being phased out, leaving the end-user with no need for a JRE. Java-based apps are expected to bundle their own Java implementation. The only folks consciously installing a JDK will be developers & server-side sysadmins.
Important:
Understand clearly the nature of the OpenJDK project, as explained in Wikipedia.
Know that Oracle has committed to feature-parity between its own branded Oracle JDK and the OpenJDK project. This commitment includes donations of previously-commercial features such as Flight Recorder and Mission Control.
OpenJFX, the open-source development of JavaFX, is a part of the OpenJDK project. OpenJFX may or may not be included in a build of OpenJDK. The Java specifications do not require JavaFX functionality.
At least two vendors provide an edition of their JDK product that comes bundled with the OpenJFX libraries:
ZuluFX from Azul Systems
LibericaFX from BellSoft
Read this white paper by Oracle of 2018-03, Java Client Roadmap Update
Read the white paper Java Is Still Free, authored by key members of the Java community.
Here is a flowchart diagram that may help you finding and deciding amongst the various vendors providing a Java 11 implementation.
You can bundle a whole JDK with your app and create a batch script to run your app using the bundled JDK. I know this approach will bloat up your release significantly, but the alternative is to ask your user to install JDK themselves, which is not trivial for non-tech savvy people. Or you can release both versions, one with JDK bundled and one without.
Maybe you just wait a little bit until the first EA release of the new jpackager tool is available. See http://mail.openjdk.java.net/pipermail/core-libs-dev/2018-October/056186.html
Native Libraries
A challenge I encountered was to inform JavaFX about it's own native libraries (.dll, .dylib, .so, etc). Fortunately, getting the dylibs loaded is as simple as setting the java.library.path using System.setProperty(...).
Historically, setting this variable is argued/perceived as pointless in Java as it's too late for the classloader (inferior to -Djava.library.path) and forcing it using reflection is a forbidden security violation since Java 10... fortunately, JavaFX actually honors this variable naturally without any violations or hacks and will pick it up after it's set.
// Detect the path to the currently running jar
String jarPath = new File(this.getClass().getProtectionDomain().getCodeSource().getLocation().getPath()).getCanonicalPath();
// Fix characters that get URL encoded when calling getPath()
jarPath = URLDecoder.decode(jarPath, "UTF-8");
String parentFolder = new File(jarPath).getParent();
// If libglass.dylib is next to the jar in a folder called "/bin"
System.setProperty("java.library.path", parentFolder + "/bin");
// ... then make any javafx calls
Java Libraries
Naturally, the .jar files need to be accessible too. I do this the same as I would any java bundle by zipping them into the distribution (making a single, large .jar file)
These .jar files should be consistent with all JavaFX 11 distributions and should be bundled accordingly.
javafx-swt.jar
javafx.base.jar
javafx.controls.jar
javafx.fxml.jar
javafx.graphics.jar
javafx.media.jar
javafx.swing.jar
javafx.web.jar
Java 8 Compatibility
Initial tests against Java 8 using the above technique are positive. For now, I'm using Java version detection (not included in the above example) and ONLY setting java.library.path for Java 11 or higher. Java 8 is EOL for personal use Dec 2019 (EOL for commercial use Jan 2019) so it is important to offer compatibility as clients migrate from one LTS release to another.
(Using jdk14)
Starting by the fact that in order to use jlink your main jar should be a module.
How? Consider that you have a maven project. You just need to include module-info.java inside src/main/java dir and make sure that you require the modules that your app needs and you export the package that contains your main class. In most cases you will get a compile-time error when missing a requires. Have in mind that non-modular dependencies become automatic modules.
You can use maven's copy-dependencies to make sure that all dependencies are copied under target/lib during mvn package.
next step: jlink
Since jlink maven plugin is still in alpha, you can use command-line.
NOTES:
jlink will create a self-contained bundle directory that contains
main app module
app dependencies
jdk required modules
app launcher (optional)
jlink bundle targets one platform at a time. By default it is the current platform.
javafx runtime modules are also platform-specific. But since they are not part of the jdk we need to always provide the module-path containing them.
javafx runtime modules can be downloaded from web, or from maven repo by using the corresponding target platform classifier (win/linux/mac).
jlink can also create cross-platform bundles. Just include the target platform modules to the --module-path (e.g. from linux: download windows jdk/ javafx and add their jmods dirs to module-path).
jlink command
Case 1: build and target platforms are the same
NOTE: /path-to/javafx-mods needs to be provided to your modulepath unless you copy the required javafx deps under lib/ using maven (copy-dependencies).
jlink --launcher run=jdk14Example/com.example.javafx.app.Main \
--module-path ./lib:javafx-jdk14-example-1.0.0.jar:/path-to/javafx-mods \
--add-modules=jdk14Example --output app-bundle
Case 2: build and target platforms are differrent
# Building from linux for windows
jlink --launcher run=jdk14Example/com.example.javafx.app.Main \
--module-path ./lib:javafx-jdk14-example-1.0.0.jar:/path-to/jdk-win/jmods:/path-to/javafx-mods-win \
--add-modules=jdk14Example --output app-bundle
Conclusion:
In both of the above cases you get a directory with a self-contained application which can run on a workstation with no java/javafx installed.
# if jlink targeted linux
app-bundle/bin/run
# if jlink targeted windows
app-bundle/bin/run.bat
# if jlink targeted mac
app-bundle/bin/run
I have problem importing import "javafx.util.Pair" into my program.
after searching the net I've found this answer cannot resolve symbol javafx.application in IntelliJ Idea IDE and I've installed desired jar file but still I've problem to import.
this is what I face to when open java jdk.
I don't know the why the "jfxrt.jar" is different.
note the black arrow on the folder icon
open the File | Project Structure dialog, there under Platform Settings select SDKs and then your JDK 1.8. On the right you then see all the jars that make up the classpath to your SDK. Make sure that your jfxrt.jar is in that list, if not, you can add it by clicking the '+' button at the bottom.
Update May 2020
JavaFX is no longer part of the Oracle or OpenJDK default distributions. Instead it is available as a seperate library or module set.
For instructions on using JavaFX in your application, see the documentation at:
https://openjfx.io
For instructions on working with a modern JavaFX installation and Idea, also see the related question:
IntelliJ can't recognize JavaFX 11 with OpenJDK 11
You don't need to "install the desired jar" (whatever that means).
You don't need to do that for JavaFX. You should not do anything explicitly with jfxrt.jar either in the filesystem or by adding it to a project classpath. If doing something on the filesystem, that is especially bad as jfxrt.jar is not made to be standalone and requires related native libraries shipped with the JDK in order to work.
The JavaFX code should be part of the JDK installation you are using. Perhaps you are using a Java version below 8 or an OpenJDK implementation that does not include JavaFX. If so, then install the Oracle JDK 8+ and set idea to use it. Everything should just work then and all of related JavaFX imports will resolve.
How do I stop maven from constantly updating my Java System Library from JDK 1.8 back to Java SE 1.8? I have configured the build path and I even set my Java_Home Variable to the JDK path. I have also have updated the build configuration. Can someone please specify how to do this with some specific instructions as I am a novice. I also noticed this keeps changing back as well. FYI I am using Eclipse Mars if that matters.
In Regards to the comments below I have shared the Eclipse M2e Plugin screenshot. Even when selected I am not able to proceed to next. I also have shown what's already installed just in case another plugin is hindering me from using the m2e
You need to understand what an Execution Environment (EE) is in Eclipse. The concept of EE is an abstraction over JREs, allowing projects to be configured without absolute paths to JRE locations. From the wiki page:
Execution environments (EEs) are symbolic representations of JREs. For example, rather than talking about a specific JRE, with a specific name at a specific location on your disk, you can talk about the J2SE-1.4 execution environment. The system can then be configured to use a specific JRE to implement that execution environment.
In general, it's not advisable to configure a project to use "Workspace default" as its JRE System Library, because that makes the project inconsistent when loaded into different workspaces. Think about this: what if the project is being developed targeting Java 7, but I pull it into my workspace which has JDK 8; that could be a big problem. By using an EE, the project is configured such that it doesn't know (or care) where I actually have a matching JRE on my system.
I said all that to set up the answer for you, so you understand what Maven is doing and these instructions are doing. m2e, the Maven integration plugin for Eclipse, is (rightly) setting the project configuration to use an EE instead of "workspace default". From your screen shot I can see that you have both JDK and JRE 1.8 set up in your workspace, so ideally you should remove one (the JRE). Got to Preferences > Java > Installed JREs. There you'll see both the JRE and JDK listed. I suggest removing the JRE*.
Then go into the "Execution Environments" preferences section, select JavaSE-1.8 and make sure that your JDK is checked as the default implementation.
Now when m2e configures your projects to use an EE, that EE will be pointing to the JDK you have installed. And if someone else imports the project, it will point to wherever they have a matching JDK installed.
*By the way, it's perfectly acceptable and normal to have different versions of Java there; I often work on different projects that target different Java versions.
I have Java 8 and I've been trying to use a JAR package that uses JRE 6.
In 'Create a Java Project' I used the 'Use a project specific JRE' and also
created a run configuration but when I try to set the alternate JRE to 6, the 'run' button gets blocked out. Are they not compatible or am I missing a step? I've also tried changing the PATH destination, though I'm not sure if that is even relevant to my problem.
EDIT: I am using a JAR package from an online source that is Java 6 compatible and am trying to integrate it into Eclipse Mars with Java 8 installed.
A few items to check, under Project settings: (most of these can be set workspace-wide as well)
Java Build Path > Libraries. Replace JRE System Library with a jdk6 execution environment or alternate JRE
Java Compiler > JDK compliance. Set to 1.6
System:
Check Installed JREs and Execution environments. Make sure a JRE is linked to the Execution Environment for JavaSE-1.6 (with the checkbox).
Did you try just adding the external JAR to the project? Most (non-executable) JARs that were originally made for older versions of java should still work today.
To add an external JAR: right-click on your project in the package explorer and go to Build Path >> Add External Archives... then select your JAR from there. Be sure to leave the project set up for JRE8.
The reason that your run button is blocked out when you switched to JRE6 was because Eclipse detected that it was not installed and therefore cannot run it as JRE6.