spring-projects / spring-framework

Spring Framework
https://spring.io/projects/spring-framework
Apache License 2.0
56.64k stars 38.14k forks source link

IllegalAccessError for some auto-configured beans when enabling AspectJ load time weaving #31300

Open pdeneve opened 1 year ago

pdeneve commented 1 year ago

Created this issue as suggested here.

To enable AspectJ load time weaving in a Spring application, one would use the @EnableLoadTimeWeaving annotation as outlined in the Spring reference documention. Due to issue 29609 this is not working and a workaround proposed involves registering AspectJWeavingEnabler and DefaultContextLoadTimeWeaver upfront when instantiating the application context. For a spring boot application, this looks as follows:

SpringApplication.run(new Class[] { Config.class, AspectJWeavingEnabler.class, MyLoadTimeWeaver.class }, args);

With MyLoadTimeWeaver extending DefaultContextLoadTimeWeaver and annotated with @Component("loadTimeWeaver") because the name of the LoadTimeWeaver bean "loadTimeWeaver" is expected by the framework.

When running the application, some auto-configured beans cannot be accessed anymore. E.g. for the spring.boot.ltw module in this repository, the following stacktrace is produced:

org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'dataSourceScriptDatabaseInitializer' defined in class path resource [org/springframework/boot/autoconfigure/sql/init/DataSourceInitializationConfiguration.class]: Unsatisfied dependency expressed through method 'dataSourceScriptDatabaseInitializer' parameter 0: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:800) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:550) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1332) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1162) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:560) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:313) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1155) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:608) ~[spring-context-6.0.11.jar:6.0.11]
        at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:436) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-3.1.2.jar:3.1.2]
        at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-3.1.2.jar:3.1.2]
        at be.pdn.training.aspectj.spring.boot.ltw.Main.main(Main.java:9) ~[classes/:na]
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'dataSource' defined in class path resource [org/springframework/boot/autoconfigure/jdbc/DataSourceConfiguration$Hikari.class]: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:605) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:520) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:326) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:324) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.config.DependencyDescriptor.resolveCandidate(DependencyDescriptor.java:254) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1417) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1337) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.resolveAutowiredArgument(ConstructorResolver.java:888) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:791) ~[spring-beans-6.0.11.jar:6.0.11]
        ... 19 common frames omitted
Caused by: java.lang.IllegalAccessError: failed to access class org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails from class org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor (org.springframework.boot.autoconfigure.jdbc.PropertiesJdbcConnectionDetails is in unnamed module of loader 'app'; org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor is in unnamed module of loader org.springframework.context.support.ContextTypeMatchClassLoader$ContextOverridingClassLoader @159e366)
        at org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetailsBeanPostProcessor.postProcessBeforeInitialization(JdbcConnectionDetailsBeanPostProcessor.java:54) ~[spring-boot-autoconfigure-3.1.2.jar:3.1.2]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:419) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1762) ~[spring-beans-6.0.11.jar:6.0.11]
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:598) ~[spring-beans-6.0.11.jar:6.0.11]
        ... 29 common frames omitted

To reproduce yourself:

It is possible to workaround this issue by defining manually the beans for which an IllegalAccessError occurs. E.g. for the sample project, uncomment the @Bean annotation for the JdbcConnectionDetails bean in Config.java and it will work.

snicoll commented 10 months ago

@pdeneve I don't think the instruction to reproduce are correct. Shouldn't we do something before exec:exec?

pdeneve commented 10 months ago

@snicoll Thanks for having a look. You're right, you need to run mvn compile before. I've updated the instructions. Please note I've just updated all dependencies, so please pull. The updated instructions apply to the new version.