Bug 541804 - Need automated API compatibility check if compilation target version differs from JDK version
Summary: Need automated API compatibility check if compilation target version differs ...
Status: NEW
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 4.10   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: ---   Edit
Assignee: JDT-Core-Inbox CLA
QA Contact:
URL:
Whiteboard: stalebug
Keywords:
Depends on:
Blocks:
 
Reported: 2018-12-03 02:44 EST by Luke Hutchison CLA
Modified: 2022-11-30 11:05 EST (History)
2 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Luke Hutchison CLA 2018-12-03 02:44:30 EST
Given a ByteBuffer buf, the following call (or calling any other method apparently defined in the superclass Buffer of ByteBuffer) breaks _at runtime_ if compiled using JDK 9+ in JDK 7/8 compatibility mode, then run in JRE 7/8:

    buf.mark();

The error is "java.lang.NoSuchMethodError: java.nio.ByteBuffer.mark()Ljava/nio/ByteBuffer;". The way to fix this is to call instead:

    ((Buffer) buf).mark();

The problem is that JDK 9 added proxy methods to ByteBuffer of the same name as the Buffer methods that return "this" as a ByteBuffer, rather than as a Buffer.

It's rather stupid that this change would break source-level compatibility like this (especially when the return value is not even used, but is discarded!). But buf.mark() calls a JDK 9+-specific method if compiled in JDK 9+, even in JRE 7/8 compatibility mode.

It is really undesirable to have to add API-specific warnings to an IDE. But this problem is weird enough, and disruptive enough, that it is really probably worth it to have Eclipse warn in this case.

maven-enforcer-plugin (Animal Sniffer) at least gives the following warning if checked against the Java 1.7 API, which is not really helpful unless you're familiar with return type covariance, and how this can break an API, but it's a start:

Covariant return type change detected: java.nio.Buffer java.nio.ByteBuffer.position(int) has been changed to java.nio.ByteBuffer java.nio.ByteBuffer.position(int)
Comment 1 Stephan Herrmann CLA 2018-12-03 11:33:52 EST
Would the problem also happen if you compile with --release 7?
Comment 2 Luke Hutchison CLA 2018-12-03 13:54:04 EST
I read a comment somewhere where somebody said that the release switch should fix the problem, but there wasn't a confirmation as to whether or not that was the case, and I didn't test it, because for my project it's not an option -- the project has to be compilable on older or newer JDKs, but always targeting JDK 7 and 8. The release switch was only added to newer JDKs.
Comment 3 Luke Hutchison CLA 2018-12-03 14:00:14 EST
The other problem is that the JDK 11 javadoc doesn't even describe the change. It only shows the methods defined in the superclass Buffer, and not the fact that those methods were "overridden" (actually masked, not overridden, since the return type changed) in the subclass ByteBuffer. So the breakage is mystifying, and virtually impossible to understand without looking at the jdk source, and/or googling for why on earth this breaks at runtime.
Comment 4 Stephan Herrmann CLA 2018-12-04 07:38:13 EST
Let me re-check if I understand correctly: 

(1) The error occurs only if you compile against JRE 9 but run on JRE 7 or 8.

(2) You want JRE 7 compatibility so that users can run the software on JRE 7

(3) You want contributors to build the software on any of JRE 7, 8 or 9.


In former times, it was strongly discouraged to compile against a JRE that differs from the target, because arbitrary NoSuchMethodErrors could happen. So assuming that the software can be built against arbitrary JREs with no differences has never been a good idea.

My point is that starting with Java 9 you actually have a systematic solution to all these issues. Hence the safest three options would IMHO be:
- your software targeting 7 must always be built against JRE 7 (old style)
- your software must be built against JRE 9+ with "--release 7" (new style)
- your build by default declares "--release 7" and you inform contributors
  who don't have a JRE 9+ (why would that be in the first place??) that they 
  need to remove the "--release 7" switch.

I understand that the current problem is mystifying, but special-casing individual classes and members of the JRE during compilation in order to support a broken build-setup sounds like a bad trade-off to me.


@Jay, as an extra courtesy to users not having JRE 9+, would it make sense to simply ignore "--release 7" when the target JRE is not multi-release but actually conformant to the requested release? Would that be "legal"? If the JRE is version 7 it seems OK. What if "--release 7" is used compiling against JRE 8??
Comment 5 Luke Hutchison CLA 2018-12-04 11:30:15 EST
Points (1)-(3) are correct, and I understand your argument of "if you do this thing you're not really supposed to do, and it breaks, you get to keep both pieces".

However, the fact remains that it is a core feature of Eclipse to be able to compile code in any JDK for any supported target version. Therefore, arguably it should also be a core feature of Eclipse to warn users where that is going to break.

Let me modify my proposal a feature request to incorporate Animal Sniffer API checking directly into Eclipse, so that whenever you compile for a specific target version, any version compatibility warnings (such as this covariant return type breakage) are displayed inline to the user.

https://github.com/mojohaus/animal-sniffer
Comment 6 Jay Arthanareeswaran CLA 2018-12-04 11:41:18 EST
(In reply to Stephan Herrmann from comment #4)
> @Jay, as an extra courtesy to users not having JRE 9+, would it make sense
> to simply ignore "--release 7" when the target JRE is not multi-release but
> actually conformant to the requested release? Would that be "legal"? If the
> JRE is version 7 it seems OK. What if "--release 7" is used compiling
> against JRE 8??

In a command line compiler, obviously the --release option is not supported in JDK < 9. I need to check what we do in the IDE in that case. Even if we do allow it in the IDE, I am pretty sure the effect is as good as ignoring the release option because a JDK 8 doesn't have the Java 7 libraries I need.
Comment 7 Eclipse Genie CLA 2020-11-25 11:49:50 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.
Comment 8 Luke Hutchison CLA 2020-11-25 13:02:57 EST
Commenting to prevent auto-closure. I still think Eclipse needs to incorporate Animal Sniffer as a post-compilation verification step for ecj.
Comment 9 Eclipse Genie CLA 2022-11-30 11:05:48 EST
This bug hasn't had any activity in quite some time. Maybe the problem got resolved, was a duplicate of something else, or became less pressing for some reason - or maybe it's still relevant but just hasn't been looked at yet.

If you have further information on the current state of the bug, please add it. The information can be, for example, that the problem still occurs, that you still want the feature, that more information is needed, or that the bug is (for whatever reason) no longer relevant.

--
The automated Eclipse Genie.