Issue
I'm creating a JavaFX Application using IntelliJ and OpenJDK 17. The project language level is set to 17. After creating the JAR (building the artifact) I try to execute it with the JRE 1.8.0_311. When I do that I get this error:
java.lang.UnsupportedClassVersionError: Main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:756)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:473)
at java.net.URLClassLoader.access$100(URLClassLoader.java:74)
at java.net.URLClassLoader$1.run(URLClassLoader.java:369)
at java.net.URLClassLoader$1.run(URLClassLoader.java:363)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:362)
at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:601)
Error: A JNI error has occurred, please check your installation and try again
Exception in thread "main"
To my understanding, this error means that my code is compiled with Java 17 but my JRE can run only Java 8 code. I tried running the .jar with the OpenJDK and it works.
Thanks in advance.
Solution
Yes, you understand the problem correctly: An app compiled for Java 17 cannot be run on a Java 8 runtime.
You have choices:
- Change your runtime to Java 17.
- Compile your app for Java 8, if your codebase does not use features from Java 9 and later.
- Bundle a Java runtime within your app. This way at compile-time you have complete control, so you can compile for Java 17 while also running on Java 17.
Modern Java offers the jlink & jpackage tooling to assist with bundling a Java runtime into your app. The Java Platform Module System make it possible to strip the Java runtime down to only the parts actually used by your app.
If you feel the need and have the nerve, the cutting edge approach is to compile a native app using GraalVM technology from Oracle.
You commented:
So basically there's not a JRE for java 17?
The JRE (Java Runtime Environment) is becoming passé as Oracle no longer expects end users in general to have a Java runtime installed on their systems. The JRE was just a subset of a JDK, with some of the tools removed.
If you bundle a Java runtime as discussed above, the JRE is irrelevant as the new modern tooling will include only the parts necessary for your app.
You can obtain Java 17 implementations from any of several vendors. These vendors include, off the top of my head, Amazon, Azul Systems, Oracle, Microsoft, Adoptium, SAP, BellSoft, Pivotal, Red Hat/IBM, FreeBSD Ports & Packages. Some vendors offer support, some do not. Some charge a fee, some do not.
By the way, another option is to build your JavaFX app without a bundled Java runtime, and without the OpenJFX/JavaFX libraries. At least two vendors supply versions of their Java runtimes that include the OpenJFX/JavaFX libraries: Azul Systems (ZuluFX), and BellSoft (LibericaFX). This approach is feasible only where you or your client have control over users’ machines such as a corporate environment, a school, etc.
I suggest reading these two white papers:
- Java Client Roadmap Update, by Oracle, 2020-05.
- Java Is Still Free 3.0.0 (Oct 2021) by the Java Champions (pillars of the Java community).
Answered By - Basil Bourque
Answer Checked By - Clifford M. (JavaFixing Volunteer)