Bug 546305 - WARNING: An illegal reflective access operation has occurred - Spring Boot 2.1. openjdk11
Summary: WARNING: An illegal reflective access operation has occurred - Spring Boot 2....
Status: RESOLVED FIXED
Alias: None
Product: AspectJ
Classification: Tools
Component: LTWeaving (show other bugs)
Version: 1.9.2   Edit
Hardware: PC Windows 10
: P3 normal (vote)
Target Milestone: 1.9.4   Edit
Assignee: aspectj inbox CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2019-04-10 11:56 EDT by Steven Warwick CLA
Modified: 2021-06-18 02:11 EDT (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Steven Warwick CLA 2019-04-10 11:56:09 EDT
conditions:
java -javaagent:libs/aspectjweaver-1.9.2.jar -jar .\target\my-spring-boot-2.1-application.war
java 11

result:

----
  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v2.1.3.RELEASE)

WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access using Lookup on org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor (file: aspectjweaver-1.9.2.jar) to class java.lang.ClassLoader
WARNING: Please consider reporting this to the maintainers of org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
----
Comment 1 Steven Warwick CLA 2019-04-30 13:48:04 EDT
Removed, user request
Comment 2 Andrew Clement CLA 2019-05-01 14:07:12 EDT
If you set --illegal-access=deny then you get a useful message:

java.lang.IllegalAccessException: module java.base does not open java.lang to unnamed module @3532ec19

So then we can set --add-opens:

java --add-opens java.base/java.lang=ALL-UNNAMED -javaagent:blahblahblah

And this removes the message.  Is that a viable option for you?  I'm not sure yet if I can turn that option into something I can set in an aspectjweaver module definition.
Comment 3 Steven Warwick CLA 2019-05-01 15:28:15 EDT
this is a fine option - have implemented in production.

is this a problem with java 11?  does it need to be reported to someone?  

we are standardizing on java 11 for now.
Comment 4 Andrew Clement CLA 2019-05-01 16:50:30 EDT
I would say it isn't a bug - it is more that Java11 is more strict about who can do what. (Feels a bit like when java started requiring the use of verification stack maps in class files - there was one version of java that used them if they were there but was ok if they were missing and the requirement was going to fully be enforced for the next release).

I would think AspectJ will do things differently down the line when this is finally not possible in a later version of the JDK. I'm just not clear what the alternative is right now or I'd move to it. I do remember some folks proposing an API we'd like to see in the JDK that would be a much better solution. If/when that appears I'll move to it but I don't *think* it is there yet (although I haven't been following progress closely).  Glad you are ok with that proposed option.
Comment 5 Steven Warwick CLA 2019-05-03 05:09:15 EDT
Much thanks  -  What do you think about adding this to the aspecj getting started guides?  I imagine that it impacts alot of folks who use jdk9+ until a better solution is found.
Comment 6 Andrew Clement CLA 2019-05-03 18:22:55 EDT
I think it will definitely go in the next README. I never seem to find the time to merge readmes into the real docs. If it is the readme then people should find it on a search for the error.
Comment 7 Andrew Clement CLA 2019-05-10 16:21:58 EDT
Put the add opens option in the readme for 1.9.4
Comment 8 Alan Bateman CLA 2019-10-19 15:27:42 EDT
The other supported API in Java SE for injecting classes is Lookup.defineClass, maybe this project could look at that instead.
Comment 9 Andrew Clement CLA 2019-11-26 17:17:41 EST
Hey Alan - if you read this - what I have now is Unsafe use for older JDKs, and using the MethodHandle.Lookup.defineClass option for Java 11. However, that requirement that the Lookup instance is for the same protectiondomain/runtime package as the class being defined is still painful. Has anything changed lately to make that easier?

I saw the discussion in http://mail.openjdk.java.net/pipermail/jigsaw-dev/2018-April/013754.html a while ago and hoped there might something like the options Rafael proposed in there by now. I found a couple of JDK issues but they didn't seem to go anywhere https://bugs.openjdk.java.net/browse/JDK-8200559 / https://bugs.openjdk.java.net/browse/JDK-8205386
Comment 10 Mandy Chung CLA 2019-11-27 15:12:35 EST
Hi Andrew, can you say more how you get Lookup object?   MethodHandles::privateLookupIn intends to help the frameworks library to get a private Lookup object on a target class.  Does that help?
Comment 11 Andrew Clement CLA 2019-11-27 15:28:24 EST
Hi Mandy - what is happening is that in the middle of transforming some bytes for a class we have needed to generate a closure class to support implementation of some around advice on something in that class. I need to register that closure alongside the affected target but at the time the generation is happening, the affected target bytes are still being transformed (we're in a JVM bytecode transformer implmentation), we haven't defined the class yet, so I can't do a lookup on that target class that I want to put it alongside.

(I will admit I'm no expect in this area, please correct me if I'm wrong somewhere here...)

Due to being on Java 8 for compilation, but wanting to run on 11, it is all loaded via reflection, so rather painful to look at. I think I saw this pattern used elsewhere and it is working for me apart from that message. I'll pull out the steps here but the full painful code is below.  Am I looking up on the wrong thing?

Thanks for taking a look

MethodType defineClassMethodType =
  MethodType.methodType(Class.class, 
    new Class[]{String.class, byte[].class, int.class, int.class, ProtectionDomain.class});                 

MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup();

MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, methodHandlesLookup);        

MethodHandle defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType);     

clazz = defineClassMethodHandle.bindTo(loader).invokeWithArguments(name, bytes, 0, bytes.length);






// MethodType defineClassMethodType = MethodType.methodType(Class.class, new Class[]{String.class, byte[].class, int.class, int.class, ProtectionDomain.class});                 
Class<?> methodType_Class = Class.forName("java.lang.invoke.MethodType");                                                                                                        
Method methodTypeMethodOnMethodTypeClass = methodType_Class.getDeclaredMethod("methodType", Class.class,Class[].class);                                                          
methodTypeMethodOnMethodTypeClass.setAccessible(true);                                                                                                                           
Object defineClassMethodType = methodTypeMethodOnMethodTypeClass.invoke(null, Class.class, new Class[] {String.class,byte[].class,int.class,int.class,ProtectionDomain.class});  
                                                                                                                                                                                 
// MethodHandles.Lookup methodHandlesLookup = MethodHandles.lookup();                                                                                                            
Class<?> methodHandles_Class = Class.forName("java.lang.invoke.MethodHandles");                                                                                                  
Method lookupMethodOnMethodHandlesClass = methodHandles_Class.getDeclaredMethod("lookup");                                                                                       
lookupMethodOnMethodHandlesClass.setAccessible(true);                                                                                                                            
Object methodHandlesLookup = lookupMethodOnMethodHandlesClass.invoke(null);                                                                                                      
                                                                                                                                                                                 
// MethodHandles.Lookup lookup = MethodHandles.privateLookupIn(ClassLoader.class, methodHandlesLookup);                                                                          
Class<?> methodHandlesLookup_Class = Class.forName("java.lang.invoke.MethodHandles$Lookup");                                                                                     
Method privateLookupMethodOnMethodHandlesClass = methodHandles_Class.getDeclaredMethod("privateLookupIn",Class.class,methodHandlesLookup_Class);                                 
privateLookupMethodOnMethodHandlesClass.setAccessible(true);                                                                                                                     
Object lookup = privateLookupMethodOnMethodHandlesClass.invoke(null, ClassLoader.class, methodHandlesLookup);                                                                    
                                                                                                                                                                                 
// MethodHandle defineClassMethodHandle = lookup.findVirtual(ClassLoader.class, "defineClass", defineClassMethodType);                                                           
Method findVirtual_Method = methodHandlesLookup_Class.getDeclaredMethod("findVirtual", Class.class,String.class,methodType_Class);                                               
findVirtual_Method.setAccessible(true);                                                                                                                                          
defineClassMethodHandle = findVirtual_Method.invoke(lookup, ClassLoader.class, "defineClass",defineClassMethodType);                                                             
                                                                                                                                                                                 
// clazz = defineClassMethodHandle.bindTo(loader).invokeWithArguments(name, bytes, 0, bytes.length);                                                                             
Class<?> methodHandle_Class = Class.forName("java.lang.invoke.MethodHandle");                                                                                                    
bindTo_Method = methodHandle_Class.getDeclaredMethod("bindTo", Object.class);                                                                                                    
invokeWithArguments_Method = methodHandle_Class.getDeclaredMethod("invokeWithArguments",Object[].class);
Comment 12 Mandy Chung CLA 2019-12-09 17:40:29 EST
Hi Andrew,

I only checked your reply now.  W.r.t. compiling on JDK 8 and running on 11, Multi-Release JAR [1] should help (which allows you to code using the new APIs rather than reflection).

The example code isn't clear to me if you are still calling ClassLoader::defineClass or MethodHandles::privateLookupIn + Lookup::defineClass.  But I think I see your issue as an agent who is transforming a class to call an auxiliary class (generated by the agent) does not have the Lookup object on the target class to begin with.  Looks like you only want to inject the class in the same package as the target class and the proposed API by https://bugs.openjdk.java.net/browse/JDK-8200559 would satisfy your need.

Can you confirm my understanding?

[1] https://openjdk.java.net/jeps/238
Comment 13 Vincent THOMASSIN CLA 2021-04-06 17:45:22 EDT
This is now a probleme in jdk16 


Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.bindTo_Method" is null
java.lang.NullPointerException: Cannot invoke "java.lang.reflect.Method.invoke(Object, Object[])" because "org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.bindTo_Method" is null
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.defineClass(ClassLoaderWeavingAdaptor.java:1102)
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor.access$300(ClassLoaderWeavingAdaptor.java:66)
	at org.aspectj.weaver.loadtime.ClassLoaderWeavingAdaptor$SimpleGeneratedClassHandler.acceptClass(ClassLoaderWeavingAdaptor.java:150)
	at org.aspectj.weaver.tools.WeavingAdaptor$WeavingClassFileProvider$1.acceptResult(WeavingAdaptor.java:920)
	at org.aspectj.weaver.bcel.BcelWeaver.weaveAndNotify(BcelWeaver.java:1434)
	at org.aspectj.weaver.bcel.BcelWeaver.weave(BcelWeaver.java:1195)
	at org.aspectj.weaver.tools.WeavingAdaptor.getWovenBytes(WeavingAdaptor.java:551)
	at org.aspectj.weaver.tools.WeavingAdaptor.weaveClass(WeavingAdaptor.java:387)
	at org.aspectj.weaver.loadtime.Aj.preProcess(Aj.java:116)
	at org.aspectj.weaver.loadtime.ClassPreProcessorAgentAdapter.transform(ClassPreProcessorAgentAdapter.java:51)
	at java.instrument/java.lang.instrument.ClassFileTransformer.transform(ClassFileTransformer.java:244)
	at java.instrument/sun.instrument.TransformerManager.transform(TransformerManager.java:188)
	at java.instrument/sun.instrument.InstrumentationImpl.transform(InstrumentationImpl.java:565)
	at java.base/java.lang.ClassLoader.defineClass1(Native Method)
	at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1010)
	at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:150)
	at java.base/java.net.URLClassLoader.defineClass(URLClassLoader.java:512)
	at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:420)
	at java.base/java.net.URLClassLoader$1.run(URLClassLoader.java:414)
	at java.base/java.security.AccessController.doPrivileged(AccessController.java:691)
	at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:413)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:586)
	at org.springframework.boot.loader.LaunchedURLClassLoader.loadClass(LaunchedURLClassLoader.java:151)
	at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:519)
	at java.base/java.lang.Class.forName0(Native Method)
	at java.base/java.lang.Class.forName(Class.java:466)
	at org.springframework.util.ClassUtils.forName(ClassUtils.java:284)
	at org.springframework.beans.factory.support.AbstractBeanDefinition.resolveBeanClass(AbstractBeanDefinition.java:469)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doResolveBeanClass(AbstractBeanFactory.java:1607)
	at org.springframework.beans.factory.support.AbstractBeanFactory.resolveBeanClass(AbstractBeanFactory.java:1534)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.determineTargetType(AbstractAutowireCapableBeanFactory.java:693)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.predictBeanType(AbstractAutowireCapableBeanFactory.java:663)
	at org.springframework.beans.factory.support.AbstractBeanFactory.isFactoryBean(AbstractBeanFactory.java:1670)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.doGetBeanNamesForType(DefaultListableBeanFactory.java:570)
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanNamesForType(DefaultListableBeanFactory.java:542)
	at org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationCondition.checkServletRegistration(DispatcherServletAutoConfiguration.java:187)
	at org.springframework.boot.autoconfigure.web.servlet.DispatcherServletAutoConfiguration$DispatcherServletRegistrationCondition.getMatchOutcome(DispatcherServletAutoConfiguration.java:167)
	at org.springframework.boot.autoconfigure.condition.SpringBootCondition.matches(SpringBootCondition.java:47)
	at org.springframework.context.annotation.ConditionEvaluator.shouldSkip(ConditionEvaluator.java:108)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:226)
	at org.springframework.context.annotation.ConfigurationClassParser.processMemberClasses(ConfigurationClassParser.java:372)
	at org.springframework.context.annotation.ConfigurationClassParser.doProcessConfigurationClass(ConfigurationClassParser.java:272)
	at org.springframework.context.annotation.ConfigurationClassParser.processConfigurationClass(ConfigurationClassParser.java:250)
	at org.springframework.context.annotation.ConfigurationClassParser.processImports(ConfigurationClassParser.java:600)
	at org.springframework.context.annotation.ConfigurationClassParser.access$800(ConfigurationClassParser.java:111)
	at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.lambda$processGroupImports$1(ConfigurationClassParser.java:812)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorGroupingHandler.processGroupImports(ConfigurationClassParser.java:809)
	at org.springframework.context.annotation.ConfigurationClassParser$DeferredImportSelectorHandler.process(ConfigurationClassParser.java:780)
	at org.springframework.context.annotation.ConfigurationClassParser.parse(ConfigurationClassParser.java:193)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.processConfigBeanDefinitions(ConfigurationClassPostProcessor.java:336)
	at org.springframework.context.annotation.ConfigurationClassPostProcessor.postProcessBeanDefinitionRegistry(ConfigurationClassPostProcessor.java:252)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanDefinitionRegistryPostProcessors(PostProcessorRegistrationDelegate.java:285)
	at org.springframework.context.support.PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors(PostProcessorRegistrationDelegate.java:99)
	at org.springframework.context.support.AbstractApplicationContext.invokeBeanFactoryPostProcessors(AbstractApplicationContext.java:751)
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:569)
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:144)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:767)
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:759)
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:426)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:326)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1311)
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1300)
	at fr.vinthec.StarterApplication.main(StarterApplication.java:19)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:78)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:567)
	at org.springframework.boot.loader.MainMethodRunner.run(MainMethodRunner.java:49)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:107)
	at org.springframework.boot.loader.Launcher.launch(Launcher.java:58)
	at org.springframework.boot.loader.JarLauncher.main(JarLauncher.java:88)
Comment 14 Alexander Kriegisch CLA 2021-06-18 02:11:06 EDT
I can comfirm that for the upcoming AspectJ 1.9.7 we do not have a solution, but instead are documenting the need to use this on JDK 16+:

--add-opens java.base/java.lang=ALL-UNNAMED

https://github.com/eclipse/org.aspectj/blob/d17189c430a7ffd1ec966759a93b3ed348766650/docs/dist/doc/README-197.html#L71-L79

I only started contributing to AspectJ a few months back and am not competent (yet) to find out, if we can avoid that. Unfortunately, Andy is busy and did not have time to dig in either. If we cannot find a solution, this additional CLI parameter might well be a deal breaker for many users in the future with regard to AspectJ LTW.

@Andy, can you maybe comment on this, answering Mandy's question?

> I think I see your issue as an agent who is transforming a class to call
> an auxiliary class (generated by the agent) does not have the Lookup
> object on the target class to begin with.  Looks like you only want to
> inject the class in the same package as the target class and the proposed
> API by https://bugs.openjdk.java.net/browse/JDK-8200559 would satisfy your
> need.
> 
> Can you confirm my understanding?