0

I have a Spring Framework 4.2 project that I can successfully compile with JDK 11 and run with Wildfly that is utilizing Java 11.

I'm looking at upgrading to use Wildfly v26 which utilizes Java 17. Seems like it would work since newer versions of Java are supposed to be able to run code compiled against earlier versions of Java.

My skepticism about this particular project comes from the fact that if I use JDK 17 and attempt to compile my project against Java 11 (via Maven), I get errors related to cglib which is part of Spring Framework.

From what I understand, cglib calls internal functions that are not publicly accessible and Java 17 doesn't support that.

So, I'm lacking some understanding here: the Java 17 JRE is supposed to be able to run earlier versions of Java code (as far as I understand), however my JDK 17 can't seem to compile code targeting Java 11. I thought this is a capability we're supposed to have - compiling code for earlier versions with newer versions of the JDK. Perhaps this is one of those edge case scenarios where the actual issue would require a compilation using JDK 11 and then, and only then, would it be able to run with JRE 17.

So, the overarching question is: Can I get my code targeting Java 11 to run (in ANY way) with Java 17 given this particular issue?

Bonus question: What about the compatibility between a JDK, compilation target and runability am I misunderstanding here?

Ryan Griffith
  • 1,591
  • 17
  • 41
  • 1
    The problem is that Spring uses cglib to rewrite Java bytecode on-the-fly at runtime and, as you said, the internal APIs it uses are protected in more recent versions of the JVM. This is much more than just running "earlier versions of Java code." I'm pretty sure that newer versions of Spring use newer versions of either cglib or other bytecode-rewriting libraries that do work on newer JVMs. Is there some reason you are stuck on a version of Spring from 2015? – David Conrad Jun 08 '23 at 15:56
  • [This question and answer](https://stackoverflow.com/a/67006749/636009) have some additional details that might help to clarify matters. – David Conrad Jun 08 '23 at 15:57
  • 1
    It is not an issue with the target of your project. The spring version you use is not compatible with Java 17. – aled Jun 08 '23 at 16:05
  • @DavidConrad, upgrading a major Spring version is out of the question. This project is being decommissioned but we're doing one last upgrade for security reasons. – Ryan Griffith Jun 08 '23 at 16:10
  • Unfortunately, then, your question becomes, "How can I run this version of Spring, which is not compatible with Java 17, on Java 17?" – David Conrad Jun 08 '23 at 16:14
  • @DavidConrad, I understand the reason why `cglib` is not working if I were compiling against Java 17. I'm trying to understand the rules about how a newer JDK imposes conditions on earlier versions of Java whether those are conditions **during compilation** against earlier versions or conditions against **running** earlier versions. The confusion comes from my understanding that "Newer versions of Java should be able to run earlier versions of Java". – Ryan Griffith Jun 08 '23 at 16:16
  • The [Wildfly 26 release notes](https://www.wildfly.org/news/2021/12/16/WildFly26-Final-Released/) state that it has been tested on Java 11. – David Conrad Jun 08 '23 at 16:16
  • I understand "to run earlier versions of Java" as being backwards compatible in execution of Java bytecode compiled with a previous version. That works for sure. However if said code has assumptions on features or standard libraries that have changed over the releases then it may hit issues at execution time. This is exactly what is happening. You are lucky if the issues will happen at compile time. Much easier to detect. This is an execution time issue though. – aled Jun 08 '23 at 16:51
  • As an example you can use JDK 17, target JDK 11 and use a class or method only available since JDK 12+. It will compile just fine, and it will execute, but it will throw a class not found/method not found exception when trying to use that missing class/method. That's because the library it was built to was the newer JDK one. The target is only the bytecode compatibility. – aled Jun 08 '23 at 16:54
  • 1
    The backwards compatibility only goes for Java, the specification. Internal APIs are not part of the specification, so they are not included in the backwards compatibility guarantee. Essentially, if a library uses internal APIs, it is tied to a particular JDK build. – Jorn Vernee Jun 08 '23 at 18:51
  • 2
    @aled "As an example you can use JDK 17, target JDK 11 and use a class or method only available since JDK 12+. It will compile just fine" this depends on whether you're properly setting the boot class path. The `--release` flag was added to prevent mistakes in that area. So, if you compile using JDK 17 and `--release 11`, then you won't be able to access Java 12+ APIs. – Jorn Vernee Jun 08 '23 at 18:53
  • @JornVernee Thanks for pointing that out. More information can be find in the answers to https://stackoverflow.com/questions/43102787/what-is-the-release-flag-in-the-java-9-compiler. I just want to clarify that this only applies to the example I mentioned and would not solve the issue the OP has at execution time. – aled Jun 08 '23 at 19:01

0 Answers0