Java: 11.0.6 Spring Framework: 5.2.4.RELEASE

In our Spring-based application we use lookup method injection. After switching to the Java 11 the beans which use the lookup method injection produces the illegal reflective access warnings.

I see the issue tracker is full of similar issues. But I believe my case is special. Please let me prove it.

I created a small demo application demonstrating my case: https://github.com/feerbach/spring-enhancer-bug The important thing is: the illegal reflective access warning occurs in case the bean declared with the lookup method injection references an interface in the class attribute.

If the demo application is executed with the --illegal-access=debug VM option it produces error like:

WARNING: Illegal reflective access by org.springframework.cglib.core.ReflectUtils (file:/Users/sgarifulin/.gradle/caches/modules-2/files-2.1/org.springframework/spring-core/5.2.4.RELEASE/155344a8b1a5e98c03c0a102b2aa008d2178f7a1/spring-core-5.2.4.RELEASE.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
    at org.springframework.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:533)
    at org.springframework.cglib.core.AbstractClassGenerator.generate(AbstractClassGenerator.java:363)
    at org.springframework.cglib.proxy.Enhancer.generate(Enhancer.java:582)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:110)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData$3.apply(AbstractClassGenerator.java:108)
    at org.springframework.cglib.core.internal.LoadingCache$2.call(LoadingCache.java:54)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.springframework.cglib.core.internal.LoadingCache.createEntry(LoadingCache.java:61)
    at org.springframework.cglib.core.internal.LoadingCache.get(LoadingCache.java:34)
    at org.springframework.cglib.core.AbstractClassGenerator$ClassLoaderData.get(AbstractClassGenerator.java:134)
    at org.springframework.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:319)
    at org.springframework.cglib.proxy.Enhancer.createHelper(Enhancer.java:569)
    at org.springframework.cglib.proxy.Enhancer.createClass(Enhancer.java:416)
    at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$CglibSubclassCreator.createEnhancedSubclass(CglibSubclassingInstantiationStrategy.java:154)
    at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy$CglibSubclassCreator.instantiate(CglibSubclassingInstantiationStrategy.java:116)
    at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:84)
    at org.springframework.beans.factory.support.CglibSubclassingInstantiationStrategy.instantiateWithMethodInjection(CglibSubclassingInstantiationStrategy.java:76)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:91)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(AbstractAutowireCapableBeanFactory.java:1312)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1214)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:557)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:222)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:321)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:879)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:878)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:550)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:747)
    at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:397)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:315)

Here it is a snippet from the xml application context file of the demo application:

<bean id="someBean" scope="prototype" class="com.example.demo.SomeBean"/>

<bean id="someFactory" class="com.example.demo.SomeFactory">
    <lookup-method name="getBean" bean="someBean"/>
</bean>

The com.example.demo.SomeFactory is an interface. Under the hood the Spring creates an org.springframework.cglib.proxy.Enhancer instance to generate implementation class of the someFactory bean. In the debugger I see the Enhancer instance passes null as the contextClass when it invokes the ReflectUtils.defineClass method.

The contextClass field of the Enhancer instance created for the someFactory bean is not initialized: when the Enhancer instance is being created the Enhancer.setSuperclass is called with the com.example.demo.SomeBean interface as the superclass argument but the contextClass field is initialized only if the passed superclass is a concrete class.

The question is: was it intended the Enhancer does not specify contextClass in case the superclass is an interface?