Like many other projects (Tomcat, MongoDB, etc.) compiling with JDK 9+ with release 8 produces incorrect bytecode for these ByteBuffer methods:
position(int)
limit(int)
mark​()
reset​()
clear()
flip()
rewind​()
Running a Jetty compiled with JDK 9+ with release 8 in a JDK 8 JVM will produce a NoSuchMethodError.
The solution is to cast the ByteBuffer to Buffer when calling those methods:
((Buffer)byteBuffer).position(0);
To be clear this is because Java 9 introduced a Covariant return type that when compiled with Java 9+ includes the return type in the (jetty) bytecode, rendering the bytecode incompatible with Java 8.
Right?
@joakime correct.
The call byteBuffer.position(0) in JDK 8 calls method Buffer.position(I)LBuffer while in JDK 9+ calls method ByteBuffer.position(I)LByteBuffer.
When a JVM 8 sees the latter it does not find it, hence the error.
I'm still astonished that JDK 9's javac produces the wrong bytecode even when specifying --release 8.
REALLY??? ugh!
But should be a simple fix if we have all been using BufferUtil like we should be :)
However, we don't want to "fix" this in jetty-10 as that is never intended to be run on java8, so do we just need to fix this in jetty-9?
@gregw, correct we only need it in 9.4.x.
I also run into this problem, any update upon this ?
@DreamWuGit to work around, in your project, compile with JDK8, run with any JDK.
@joakime but the problem is that Maven Central artifacts that we produce are compiled with JDK 9+.
Sorry to butt in here, but I see this and several other projects adding unnecessary casts for this issue. I have never seen javac produce the wrong bytecodes when given the proper --release flag. The wrong bytecodes issue seems to occur when one is using (for example) JDK 9 and using "javac -source 8 -target 8", which does let Java 9 library dependencies leak into Java 8 classes (and which issues a warning) and which results in this problem. Usually the problem seems to be that something in the build system is still using the -source 8 -target 8 technique and thus the problem persists.
Now if javac --release 8 is still letting Java 9 dependencies into the Java 8 class files, that's a bug and we should fix it.
@stuart-marks I just double checked this and you are right, --release 8 produces the right bytecode.
We do have a profile that is automatically enabled when compiling with JDK > 8 (https://github.com/eclipse/jetty.project/blob/jetty-9.4.18.v20190429/pom.xml#L1843) that enforces --release 8 so we should be good.
Thank you, @sbordet. I'm new to Java and your comment helped me fix the issue quickly!
Most helpful comment
Sorry to butt in here, but I see this and several other projects adding unnecessary casts for this issue. I have never seen javac produce the wrong bytecodes when given the proper
--releaseflag. The wrong bytecodes issue seems to occur when one is using (for example) JDK 9 and using "javac -source 8 -target 8", which does let Java 9 library dependencies leak into Java 8 classes (and which issues a warning) and which results in this problem. Usually the problem seems to be that something in the build system is still using the-source 8 -target 8technique and thus the problem persists.Now if
javac --release 8is still letting Java 9 dependencies into the Java 8 class files, that's a bug and we should fix it.