Search code examples
javaspringspring-bootjava-17

Spring Boot can't start on JDK 17 : module java.base does not "opens java.lang" to unnamed module


I am migrating a Spring Boot app from JDK 8 to JDK 17.

But in JDK 17 I have the following error :

java.lang.reflect.InaccessibleObjectException: Unable to make protected final java.lang.Class java.lang.ClassLoader.findLoadedClass(java.lang.String) accessible: module java.base does not "opens java.lang" to unnamed module @1356d4d4
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:354) ~[na:na]
    at java.base/java.lang.reflect.AccessibleObject.checkCanSetAccessible(AccessibleObject.java:297) ~[na:na]
    at java.base/java.lang.reflect.Method.checkCanSetAccessible(Method.java:199) ~[na:na]
    at java.base/java.lang.reflect.Method.setAccessible(Method.java:193) ~[na:na]
    at org.springframework.util.ReflectionUtils.makeAccessible(ReflectionUtils.java:577) ~[spring-core-5.3.20.jar:5.3.20]
    at org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader.isEligibleForOverriding(ContextTypeMatchClassLoader.java:99) ~[spring-context-5.3.20.jar:5.3.20]
    at org.springframework.core.OverridingClassLoader.loadClass(OverridingClassLoader.java:87) ~[spring-core-5.3.20.jar:5.3.20]
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520) ~[na:na]
    at org.springframework.core.OverridingClassLoader.loadClass(OverridingClassLoader.java:82) ~[spring-core-5.3.20.jar:5.3.20]
    at org.springframework.context.support.ContextTypeMatchClassLoader.loadClass(ContextTypeMatchClassLoader.java:70) ~[spring-context-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1594) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1534) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:704) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:674) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1670) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:667) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeansOfType(DefaultListableBeanFactory.java:659) ~[spring-beans-5.3.20.jar:5.3.20]
    at org.springframework.context.support.AbstractApplicationContext.getBeansOfType(AbstractApplicationContext.java:1300) ~[spring-context-5.3.20.jar:5.3.20]
    at org.springframework.boot.SpringApplication.getExitCodeFromMappedException(SpringApplication.java:867) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.getExitCodeFromException(SpringApplication.java:855) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.handleExitCode(SpringApplication.java:842) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.handleRunFailure(SpringApplication.java:782) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:318) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar:2.7.0]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar:2.7.0]
    at com.pacinformatique.vinotech.mobile.VinotechMobileApplication.main(VinotechMobileApplication.java:42) ~[classes/:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77) ~[na:na]
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
    at java.base/java.lang.reflect.Method.invoke(Method.java:568) ~[na:na]
    at org.springframework.boot.devtools.restart.RestartLauncher.run(RestartLauncher.java:49) ~[spring-boot-devtools-2.7.0.jar:2.7.0]

Adding --add-opens java.base/java.lang=ALL-UNNAMED to the VM options works but it looks pretty hacky. I thought that with Spring Boot 2.7 I would've been able to run the app without the VM options.

Have I missed something ?


Solution

  • I discovered that my issue was not so much related to Spring Boot but more to AspectJ load time weaving.

    Indeed my project uses Load Time Weaving with AspectJ, and as we can see in the latest changelog from AspectJ :

    Use LTW on Java 16+ Please note that if you want to use load-time weaving on Java 16+, the weaving agent collides with JEP 396 (Strongly Encapsulate JDK Internals by Default) and related subsequent JEPs. Therefore, you need to set the JVM parameter --add-opens java.base/java.lang=ALL-UNNAMED in order to enable aspect weaving. This is due to the fact that the weaver uses internal APIs for which we have not found an adequate replacement yet when defining classes in different classloaders

    Therefore the VM option is need for my project for now.