I am working on a small library and for obvious reasons I would like to write code using all the Java 11 features (except modules I guess for now), but I would like the library to be compatible with Java 8 and above.
When I try this:
javac -source 11 -target 1.8 App.java
I get the following message:
warning: source release 11 requires target release 11
...and when I look at the byte code I see that the version of the class is 0x37
(Java 11):
$ xxd App.class
00000000: cafe babe 0000 0037 ...
And Java 8 cannot load it:
Exception in thread "main" java.lang.UnsupportedClassVersionError: App has been
compiled by a more recent version of the Java Runtime (class file version 55.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:763)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:468)
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:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:349)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:495)
How do people provide such compatibility? I am open to all build tools.
For me it seems easy just to transform high-level language (Java) into low-level (bytecode). It appears to me that when the high-level language changes, the low-level should stay the same. That is why I thought it was possible.
UPDATE
Guys, I don't think that this answer duplicates Move to OpenJDK-11 but compile in Java 8, because there the OP asks how to keep producing the code with Java 8
features, but target Java 11 (which is just a famous backward compatibility). My question is the other way around: I want to produce the code in Java 11, but target Java 8. I came across that question when I was researching the topic before posing the question. I didn't find it applicable to my situation.
The other question Can Java 8 code be compiled to run on Java 7 JVM does look similar to my question, but it was asked in 2013 and the bytecode obviously changed between Java 7 and Java 8.
I didn't think the bytecode changed that much since Java 8 that is why I asked this question.
--release 8
parameter which will not only generate Java 8-compatible bytecode, but it will also generate a binary which actually works with Java 8. There is a subtle difference, but it is possible to build a bytecode-compatible binary that will fail at runtime because methods in the standard library were chosen by the compiler that don't actually exist in a Java 8 standard library. The--release
option should avoid that. – Recipe