GeezerVison is showing github.com — NoSuchMethodError on JDK8 with Clojure · Issue #116 · lmdbjava/lmdbjava
NoSuchMethodError on JDK8 with Clojure #116DescriptionI'm using lmdbjava for a Clojure project. I don't think Clojure matters for this issue but it's the latest version 1.10. My project was working fine with lmdbjava 0.6.1, but failed when I tried to update to lmdbjava 0.6.2.
(This is a small bit of Clojure test failure report.)
ERROR in (larger-test) (ByteBufferProxy.java:297)
Uncaught exception, not in assertion.
expected: nil
actual: java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer;
at org.lmdbjava.ByteBufferProxy$UnsafeProxy.out (ByteBufferProxy.java:297)
org.lmdbjava.ByteBufferProxy$UnsafeProxy.out (ByteBufferProxy.java:260)
org.lmdbjava.KeyVal.valOut (KeyVal.java:133)
org.lmdbjava.Dbi.reserve (Dbi.java:465)
I'm using java version "1.8.0_192"
Java(TM) SE Runtime Environment (build 1.8.0_192-b12)
Java HotSpot(TM) 64-Bit Server VM (build 25.192-b12, mixed mode)
Interestingly, my Clojure project works on JDK 11 with either lmdbjava 0.6.1 and 0.6.2. I got it to work with JDK 8 by building lmdbjava 0.6.2 and installing it in my local maven repository. It looks like the maven central jar was built with JDK 11 so maybe that explains my problem? I'm guessing that some mvn option to target 1.8 would help, but this is just speculation. If other people can confirm that the maven central jar works with JDK 8, then I will have to investigate the Clojure inter-op problem.
Would you be willing to target JDK 8 or is that a non-starter? Activityivenhov commented on Jan 6, 2019 I got the same on Java 1.8.0_181. Works ok on LMDB 0.6.1
Exception in thread "main" java.lang.NoSuchMethodError: java.nio.ByteBuffer.clear()Ljava/nio/ByteBuffer; at org.lmdbjava.ByteBufferProxy$UnsafeProxy.out(ByteBufferProxy.java:297) at org.lmdbjava.ByteBufferProxy$UnsafeProxy.out(ByteBufferProxy.java:260) at org.lmdbjava.KeyVal.valOut(KeyVal.java:133) at org.lmdbjava.Dbi.get(Dbi.java:239)
possibly related
akka/akka-core#23755 miner commented on Jan 6, 2019 Thanks for the confirmation of the problem in pure Java. Following the akka link and related items, I found a good explanation here: https://jira.mongodb.org/browse/JAVA-2559
Java 9 introduces overridden methods with covariant return types for the following methods in java.nio.ByteBuffer that are used by the driver:
position
limit
flip
clear
In Java 9 they all now return ByteBuffer, whereas the methods they override return Buffer,
resulting in exceptions like this when executing on Java 8 and lower:
java.lang.NoSuchMethodError: java.nio.ByteBuffer.limit(I)Ljava/nio/ByteBuffer
This is because the generated byte code includes the static return type of the method, which is not found on Java 8 and lower because the overloaded methods with covariant return types don't exist.
The solution is to cast ByteBuffer instances to Buffer before calling the method.
miner commented on Jan 6, 2019 It seems like the casting works, but for long term compatibility I suggest that you try to target 1.8 and use the 1.8 class path. vladp commented on Jan 27, 2019 thx for pointing me to the duplicate issue.
Does this mean 0.6.2 will not work with java 8 (and only java 9 or above is needed)?
My code supprts freebsd/netbsd/dragonflybsd/openbsd and those do not have Java 9 or 11
in their distros yet. So I am stuck with Java 8 at the moment. miner commented on Jan 27, 2019 Yes, the 0.6.2 jar was built with JDK 11 so it will not work with JDK 8 (Java 1.8) systems. However, you can build the lmdbjava source on JDK 8 and then it will work. I did a local mvn install and everything worked for me on JDK 8. In theory, setting the build target to java 1.8 would make a compatible jar for 1.8+ but I haven't tested that. bp-alex commented on Jan 27, 2019 LmdbJava's POM does not declare a particular Java version. Instead it inherits from the Acegi Standard Project POM and this was set to 1.8.
All builds are performed by Travis and it currently supports Ubuntu releases Precise, Trusty and Xenial. These correspond to YY-MM date versions 12.04, 14.04 and 16.04 respectively.
The Travis Xenial JVM environment only supports OpenJDK 10 and 11. LmdbJava 0.6.2 was built by OpenJDK 11 on Travis Xenial, although with Java 1.8 as the compilation target as mentioned earlier.
While the Trusty JVM environment supports OpenJDK 8, I prefer to not use a distribution that is almost five years old as I write this.
The real question is whether Java 8 is appropriate to support at all. I suggest there are three key questions:
- When does Java 8 reach EOL?
- Does LmdbJava support Java 11, being the next LTS release?
- Given LmdbJava 0.6.1 works with Java 8, does semantic versioning indicate 0.6.2 should as well?
On the first point, the Oracle Java SE Support Roadmap states:
Oracle will continue to provide free public updates and auto updates of Java SE 8, until at least the end of December 2020 for Personal Users, and January 2019 for Commercial Users.
I don't think many LmdbJava users would concurrently be both Personal Users and unable to update beyond Java 8. While Commercial Users are likely to have constraints in doing so, such users are EOL as of this month. So I don't honestly think we need to support Java 8 given this month it's EOL for Commercial Users and I believe Personal Users can probably upgrade. I am sympathetic to the BSD issue faced by @vladp but it's an unusual circumstance and it would seem preferable to help the BSDs upgrade their JVM given Java 8's EOL status.
On the second point, I am using LmdbJava with Java 11. There seem to be some issues with Windows as per #97 that we need to figure out and we need more discussion around the items in #42 but LmdbJava definitely works with Java 11 on Linux.
On the third point, in my reading semantic versioning doesn't specify any requirements. However the core principle is developers should be able to take a PATCH version (so 0.6.1 to 0.6.2) without breaking their applications. So LmdbJava breaking for Java 8 between 0.6.1 and 0.6.2 is unacceptable.
I'll be pragmatic here and change the Travis build back to Trusty to work around this. But I provided the above background because I don't really like using very old software (be it Ubuntu distributions or Java versions) and there will be a point in the not-too-distant future where Java 8 is no longer supported. Before doing that we'll have Java 11 working properly across all the officially-supported operating systems (ie those for which we ship the native library within the LmdbJava JAR) and of course make sure the change is obvious at a version number point of view. ivenhov commented on Jan 28, 2019 Hi @benalexau
Thanks for your time and elaborate explanation.
I totally understand point of view and you arguments.
Let me explain my situation.
We are evaluating/using lmdbjava in commercial environment.
We have hundreds of installs of our software (server-side) across the globe. Due to various constraints we cannot follow latest/greatest Ubuntu upgrades.
There is certain risk, operational complexity, downtime associated with the upgrade etc.
In some environments only security patches are allowed.
We are on Ubuntu LTS and only this year we are switching to 16.04 and Java 8. Previously we were running 12.04 with Java 7.
In our case we prefer long-term stability and platform that we know rather than upgrading to versions that inevitably would bring in some issues.
There is still a lot of uncertainty with Java 9 modules, open source projects used as dependencies of dependencies not keeping up etc. Java 11 is still very fresh, definitely not for production use in my view.
I would love to be on the latest version of Java but reality is more complex and we will see a lot of sw running on server-side for quite some time.
From my point of view if there is no particular need to build lmdbjava and tie it to the latest Java I would prefer to have lowest reasonable Java version. If Java 7 is out of the picture, I think Java 8 is reasonable.
I believe Xenial has Java 8 by default.
If software runs on never JVM it will surely take advantage of it despite being compiled with byte-code
compatible with Java 8.
BTW JDK breaking interfaces like that ByteBuffer.clear() ConcurrentHashMap.keySet() is one of the examples of incompatibilities we have to live with. They always come up in the worst possible moment, usually in production system
Of course we can always build lmdbjava ourselves, although I would much prefer to get it as Gradle dependency.
I absolutely agree on the versioning point.
Thanks again for your time and maintaining the project.
Keep up great work.
Regards
Daniel miner commented on Jan 28, 2019 Thanks to @benalexau for the thorough response. My understanding is that you need to set the target to the older Java and configure the compiler's boot classpath to match the target JRE. My guess is that even with a target of 1.8 it still compiled against the JRE 11 boot classpath. That would explain why the published jar had Java 11 dependencies. I'm personally OK with a requirement of a newer Java as long as it's documented. I filed the bug because it looked like this was an unintentional change. It would be nice to have Java 8 compatibility just because a lot of places still use it and compatibility would avoid nasty surprises, but it's completely understandable that an open source project would choose the Java version that works best for their development process. Thanks for taking a look at this issue. bp-alex commented on Jan 29, 2019 ivenhov commented on Jan 29, 2019 Works for me. Tested on Oracle JDK 1.8.0_181 on Windows miner commented on Jan 29, 2019 0.6.3-snapshot works for me on Java 8 (with Clojure 1.10). bp-alex commented on Feb 8, 2019 Great to hear it works. I'll close this ticket and make an LmdbJava release shortly. miner commented on Feb 8, 2019 lmdbjava 0.6.3 release works for me. Thanks.
MetadataMetadataDevelopmentNo branches or pull requestsIssue actions
|