0

I have an application running in Tomcat 9.0.45 with JDK 11 (OpenJDK 11.0.11).

After upgrading some libraries (Spring 4.3.30 to 5.3.9) using maven, the application throws the following Exception:

java.lang.NoClassDefFoundError: java/lang/constant/Constable
    at my.app.SomeClass.process(SomeClass.java:123) ~[classes/:?]
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) [spring-context-5.3.9.jar:5.3.9]
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) [?:?]
    at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) [?:?]
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
    at java.base/java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: java.lang.ClassNotFoundException: java.lang.constant.Constable
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1364) ~[catalina.jar:9.0.45]
    at org.apache.catalina.loader.WebappClassLoaderBase.loadClass(WebappClassLoaderBase.java:1187) ~[catalina.jar:9.0.45]
    ... 11 more

Obviously, it tries to run JRE 12 code in a JRE 11 environment.

As the Exception does not occur prior to updating the libraries, I guess some dependency got into the project that uses the JRE 12 code.

How can I find out which library/dependency causes the problem?

WebappClassLoaderBase debug log does not give any new information:

org.apache.catalina.loader.WebappClassLoaderBase.loadClass loadClass(java.lang.constant.Constable, false)
org.apache.catalina.loader.WebappClassLoaderBase.loadClass   Searching local repositories
org.apache.catalina.loader.WebappClassLoaderBase.findClass     findClass(java.lang.constant.Constable)
org.apache.catalina.loader.WebappClassLoaderBase.findClass     --> Returning ClassNotFoundException

Strangely, the Exception does not occur on my dev machine, so I also can't debug.

Any ideas are very much appreciated.

Edit: compiling with maven 3.8.1 using aspectj-maven-plugin 1.12.6.

Manuel M
  • 809
  • 1
  • 10
  • 25
  • *Obviously, it tries to run JRE 12 code in a JRE 11 environment.* No. Something quite different would happen then. What is this oddly-named `java.lang.constant.Constable` (which isn't being found)? – g00se Jul 27 '21 at 08:10
  • Hi, what would be supposed to happen then? `java.lang.constant.Constable` is a new Interface introduced in Java 12. `java.lang.Class implements Constable`, so I guess pretty much every code compiled against Java 12 would try to load `java.lang.constant.Constable`. – Manuel M Jul 27 '21 at 08:19
  • `java.lang.UnsupportedClassVersionError` would normally occur if the compiled version were ahead of the runtime Finding the compiled version is [simple enough](https://technojeeves.com/index.php/aliasjava1/105-determine-java-class-file-version) – g00se Jul 27 '21 at 08:43
  • Also it's your code that seems to be invoking that `Constable` interface – g00se Jul 27 '21 at 08:56
  • @g00se there's no reference to `Constable` in my code - I guess its indirectly needed because of a library that gets loaded when loading the class. – Manuel M Jul 27 '21 at 09:12

2 Answers2

1

The Constable interface (javadoc) was only added in Java 12.

So, your theory that the exception / stacktrace is caused by trying to run Java 12+ code on Java 11 is correct.

It is not entirely clear why this has happened. While the most recent versions of Spring are compatible with Java 16 ... they should also run on Java 11 (and indeed Java 8). It is possible that the Spring team have messed up and shipped some JARs that have been built incorrectly. But I doubt it.

I suspect that you have made a mistake in building your code. Maybe you compiled with a Java 12+ tool chain, against the Java SE 12+ runtime using a target version of Java 11?

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
  • I also doubt that the Spring dependencies are messed up. But when I change the Spring version in `pom.xml` back to 4.3.30 and update maven, the Exception does not appear. (Also, the machine that compiles the code only has a Java 11 JDK installed.) – Manuel M Jul 27 '21 at 08:24
  • 1
    @g00se - It depends. If you had compiled it the way I described above, you wouldn't get that error. Even if Manuel didn't do that, it is clear that something has compiled something that way. – Stephen C Jul 27 '21 at 08:44
  • Turns out that the machine that compiles the code used Java 16, not Java 11 (see my answer). – Manuel M Jul 27 '21 at 09:25
0

@Stephen C pointed to the right direction - something has compiled something that way.

Turns out the machine that compiles the code, did not have Java 11 installed, but Java 16. (Still, that compiled perfectly runnable Java 11 code for Spring 4.3.30.)

I have removed Java 16 from the machine and installed Java 11 only. The code now runs without throwing the ClassNotFoundException.

As of why that happened, I still have no idea.

Manuel M
  • 809
  • 1
  • 10
  • 25
  • 3
    A type inference issue. All it needs, is the compiler being in the situation to find the common type of two types having no common superclass (other than `Object`) but implementing `Constable` in a newer version. E.g. `List.of(MethodHandles.arrayConstructor(int[].class), MethodType.methodType(int.class)).get(0).toString();` will compile and run without problems in JDK 11, but have a dependency to `Constable` in JDK 12 or newer. This should not happen when compiling with `--release 11`. – Holger Jul 27 '21 at 17:03
  • @Holger thanks for the explanation. I was using maven to compile the code. As far as I can see, `11` [should do the trick](https://www.baeldung.com/maven-java-version). However I am compiling with `aspectj-maven-plugin`, which [does not seem to have](https://dev-aspectj.github.io/aspectj-maven-plugin/compile-mojo.html) a (working) `release` parameter. – Manuel M Jul 28 '21 at 07:12