Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AspectJ proxy bean gives IllegalAccessException in Java 16 #26578

Closed
EvgeniGordeev opened this issue May 14, 2021 · 6 comments
Closed

AspectJ proxy bean gives IllegalAccessException in Java 16 #26578

EvgeniGordeev opened this issue May 14, 2021 · 6 comments
Labels
for: external-project For an external project and not something we can fix

Comments

@EvgeniGordeev
Copy link

Here is a sample project which demonstrates the issue with SB 2.4 and JDK 16 https://github.com/EvgeniGordeev/spring-boot-java-16-aspectj-proxy-error.

The application cannot start due to:

Caused by: java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @11dc3715
	at java.base/java.lang.invoke.MethodHandles.privateLookupIn(MethodHandles.java:260) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[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:567) ~[na:na]
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:574) ~[spring-core-5.3.6.jar:5.3.6]
	... 23 common frames omitted

Valid for beans with @Transactional and when SpringBootApplication combines @EnableAspectJAutoProxy and
@EnableTransactionManagement.

@philwebb
Copy link
Member

Here's the full stacktrace:

java.lang.IllegalStateException: Failed to execute CommandLineRunner
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:779) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:344) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1336) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1325) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	at com.example.Application.main(Application.java:18) ~[classes/:na]
Caused by: org.springframework.cglib.core.CodeGenerationException: java.lang.IllegalAccessException-->module java.base does not open java.lang to unnamed module @324e4822
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:578) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54) ~[spring-core-5.3.7.jar:5.3.7]
	at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
	at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.reflect.FastClass$Generator.create(FastClass.java:65) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.proxy.MethodProxy.helper(MethodProxy.java:135) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.proxy.MethodProxy.init(MethodProxy.java:76) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:216) ~[spring-core-5.3.7.jar:5.3.7]
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:688) ~[spring-aop-5.3.7.jar:5.3.7]
	at com.example.test.TestServiceImpl$$EnhancerBySpringCGLIB$$f4c9a595.toString(<generated>) ~[classes/:na]
	at java.base/java.lang.String.valueOf(String.java:3365) ~[na:na]
	at java.base/java.io.PrintStream.println(PrintStream.java:1047) ~[na:na]
	at com.example.Application.lambda$commandLineRunner$0(Application.java:25) ~[classes/:na]
	at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:795) ~[spring-boot-2.5.0-SNAPSHOT.jar:2.5.0-SNAPSHOT]
	... 5 common frames omitted
Caused by: java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @324e4822
	at java.base/java.lang.invoke.MethodHandles.privateLookupIn(MethodHandles.java:260) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78) ~[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:567) ~[na:na]
	at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:574) ~[spring-core-5.3.7.jar:5.3.7]
	... 24 common frames omitted

@philwebb
Copy link
Member

I'm going to transfer this one to the Spring Framework team for assessment. Spring Boot isn't actually involved in the proxy creation, it's a framework concern. This looks similar to spring-projects/spring-framework#26440 but there's no module-info involved in your sample.

@philwebb philwebb transferred this issue from spring-projects/spring-boot May 15, 2021
@jhoeller
Copy link

@philwebb It looks like this is yet another case of a ClassLoader mismatch on proxy creation. This warning/exception will appear any time the target ClassLoader differs from the class loader that the original class has been loaded in. We have a couple of measures in place in the meantime, in particular for Boot's restart class loader, but this still may appear in some scenarios.

There is nothing we can do about it from the framework side anymore as far as we are aware. The only way out is either --add-opens java.base/java.lang=ALL-UNNAMED or the use of a SmartClassLoader with a publicDefineClass implementation (as the main app class loader, not just in the restart class loader) in order to avoid our fallback reflective defineClass enforcement.

If any such issues come up, I'm happy to help analyzing the specific case. The most important input here is the two ClassLoader implementations/instances in use: the one that loaded the original class (base class of the CGLIB proxy) and the specified target class loader. At ReflectUtils.defineClass level, that's contextClass.getClassLoader() versus the ClassLoader loader argument.

@philwebb
Copy link
Member

I'll transfer this back to the Boot issue tracker. Devtools isn't being used with this specific example so I'm not sure how we can fix this one. I don't think we have a good way to consistently change the application classloader being used.

@philwebb philwebb transferred this issue from spring-projects/spring-framework May 17, 2021
@philwebb philwebb added the for: team-attention An issue we'd like other members of the team to review label May 17, 2021
@wilkinsona
Copy link
Member

I'm not sure how we can fix this one either. In this case contextClass is java.lang.Object so getClassLoader() returns null. The loader argument is the app class loader (jdk.internal.loader.ClassLoaders$AppClassLoader).

As far as I can tell, the failure is specific to proxying of methods defined in the JDK such as Object#toString which is the method being called in the sample. Calling testMethod() on the proxied service doesn't trigger the problem and works fine (once the sample's dependencies have been updated a little so that a transaction manager is auto-configured).

@philwebb philwebb added status: pending-design-work Needs design work before any code can be developed status: waiting-for-triage An issue we've not yet triaged and removed for: team-attention An issue we'd like other members of the team to review labels May 26, 2021
@wilkinsona
Copy link
Member

This is essentially the same problem as has just been reported in spring-projects/spring-framework#32671. Given that we don't believe there's anything we can do about it in Boot, I'm going to close this in favor of the Framework issue. I think it's likely that the outcome of that one will be a documentation update that describes the fundamental limitations of JPMS.

@wilkinsona wilkinsona closed this as not planned Won't fix, can't repro, duplicate, stale Apr 19, 2024
@wilkinsona wilkinsona added for: external-project For an external project and not something we can fix and removed status: waiting-for-triage An issue we've not yet triaged status: pending-design-work Needs design work before any code can be developed labels Apr 19, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
for: external-project For an external project and not something we can fix
Projects
None yet
Development

No branches or pull requests

4 participants