Restore user type in generated root bean definitions
This commit restores the user class in generated RootBeanDefinition instances. Previously the CGLIB subclass was exposed. While this is important in regular runtime as the configuration class parser operates on the bean definition, this is not relevant for AOT as this information is internal and captured in the instance supplier. Closes gh-33960
This commit is contained in:
@@ -84,6 +84,7 @@ import org.springframework.context.testfixture.context.annotation.LazyResourceMe
|
||||
import org.springframework.context.testfixture.context.annotation.PropertySourceConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.QualifierConfiguration;
|
||||
import org.springframework.context.testfixture.context.annotation.ResourceComponent;
|
||||
import org.springframework.context.testfixture.context.annotation.ValueCglibConfiguration;
|
||||
import org.springframework.context.testfixture.context.generator.SimpleComponent;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
@@ -438,12 +439,14 @@ class ApplicationContextAotGeneratorTests {
|
||||
@CompileWithForkedClassLoader
|
||||
class ConfigurationClassCglibProxy {
|
||||
|
||||
private static final String CGLIB_CONFIGURATION_CLASS_SUFFIX = "$$SpringCGLIB$$0";
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasCglibProxyWriteProxyAndGenerateReflectionHints() throws IOException {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean(CglibConfiguration.class);
|
||||
TestGenerationContext context = processAheadOfTime(applicationContext);
|
||||
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$0");
|
||||
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + CGLIB_CONFIGURATION_CLASS_SUFFIX);
|
||||
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$0");
|
||||
isRegisteredCglibClass(context, CglibConfiguration.class.getName() + "$$SpringCGLIB$$FastClass$$1");
|
||||
}
|
||||
@@ -455,6 +458,43 @@ class ApplicationContextAotGeneratorTests {
|
||||
.withMemberCategory(MemberCategory.INVOKE_DECLARED_CONSTRUCTORS)).accepts(context.getRuntimeHints());
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeExposeUserClassForCglibProxy() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean("config", ValueCglibConfiguration.class);
|
||||
|
||||
testCompiledResult(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
assertThat(freshApplicationContext).satisfies(hasBeanDefinitionOfBeanClass("config", ValueCglibConfiguration.class));
|
||||
assertThat(compiled.getSourceFile(".*ValueCglibConfiguration__BeanDefinitions"))
|
||||
.contains("new RootBeanDefinition(ValueCglibConfiguration.class)")
|
||||
.contains("new %s(".formatted(toCglibClassSimpleName(ValueCglibConfiguration.class)));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeUsesCglibClassForFactoryMethod() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean("config", CglibConfiguration.class);
|
||||
|
||||
testCompiledResult(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
assertThat(freshApplicationContext).satisfies(hasBeanDefinitionOfBeanClass("config", CglibConfiguration.class));
|
||||
assertThat(compiled.getSourceFile(".*CglibConfiguration__BeanDefinitions"))
|
||||
.contains("new RootBeanDefinition(CglibConfiguration.class)")
|
||||
.contains(">forFactoryMethod(%s.class,".formatted(toCglibClassSimpleName(CglibConfiguration.class)))
|
||||
.doesNotContain(">forFactoryMethod(%s.class,".formatted(CglibConfiguration.class));
|
||||
});
|
||||
}
|
||||
|
||||
private Consumer<GenericApplicationContext> hasBeanDefinitionOfBeanClass(String name, Class<?> beanClass) {
|
||||
return context -> {
|
||||
assertThat(context.containsBean(name)).isTrue();
|
||||
assertThat(context.getBeanDefinition(name)).isInstanceOfSatisfying(RootBeanDefinition.class,
|
||||
rbd -> assertThat(rbd.getBeanClass()).isEqualTo(beanClass));
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasCglibProxyUseProxy() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
@@ -493,6 +533,20 @@ class ApplicationContextAotGeneratorTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasCglibProxyWithAnnotationsOnTheUserClasConstructor() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
applicationContext.registerBean("config", ValueCglibConfiguration.class);
|
||||
testCompiledResult(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(context -> {
|
||||
context.setEnvironment(new MockEnvironment().withProperty("name", "AOT World"));
|
||||
initializer.initialize(context);
|
||||
});
|
||||
assertThat(freshApplicationContext.getBean(ValueCglibConfiguration.class)
|
||||
.getName()).isEqualTo("AOT World");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasCglibProxyWithArgumentsUseProxy() {
|
||||
GenericApplicationContext applicationContext = new AnnotationConfigApplicationContext();
|
||||
@@ -516,6 +570,10 @@ class ApplicationContextAotGeneratorTests {
|
||||
.accepts(generationContext.getRuntimeHints());
|
||||
}
|
||||
|
||||
private String toCglibClassSimpleName(Class<?> configClass) {
|
||||
return configClass.getSimpleName() + CGLIB_CONFIGURATION_CLASS_SUFFIX;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
Reference in New Issue
Block a user