Infer proxy on @Lazy-annotated injection points
This commit makes use of the new `getLazyResolutionProxyClass` on `AutowireCandidateResolver` to detect if a injection point requires a proxy. Closes gh-28980
This commit is contained in:
@@ -17,12 +17,15 @@
|
||||
package org.springframework.context.aot;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.aot.generate.GeneratedFiles.Kind;
|
||||
import org.springframework.aot.generate.GenerationContext;
|
||||
import org.springframework.aot.hint.MemberCategory;
|
||||
import org.springframework.aot.hint.RuntimeHints;
|
||||
import org.springframework.aot.hint.TypeReference;
|
||||
import org.springframework.aot.hint.predicate.RuntimeHintsPredicates;
|
||||
import org.springframework.aot.test.generator.compile.Compiled;
|
||||
@@ -44,11 +47,18 @@ import org.springframework.context.ApplicationContextInitializer;
|
||||
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
|
||||
import org.springframework.context.annotation.AnnotationConfigUtils;
|
||||
import org.springframework.context.annotation.CommonAnnotationBeanPostProcessor;
|
||||
import org.springframework.context.annotation.ContextAnnotationAutowireCandidateResolver;
|
||||
import org.springframework.context.support.GenericApplicationContext;
|
||||
import org.springframework.context.testfixture.context.generator.SimpleComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.AutowiredComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.CglibConfiguration;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.InitDestroyComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.LazyAutowiredFieldComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.LazyAutowiredMethodComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.LazyConstructorArgumentComponent;
|
||||
import org.springframework.context.testfixture.context.generator.annotation.LazyFactoryMethodArgumentComponent;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.core.io.ResourceLoader;
|
||||
import org.springframework.core.testfixture.aot.generate.TestGenerationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
@@ -93,6 +103,87 @@ class ApplicationContextAotGeneratorTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasLazyAutowiringOnField() {
|
||||
testAutowiredComponent(LazyAutowiredFieldComponent.class, (bean, generationContext) -> {
|
||||
Environment environment = bean.getEnvironment();
|
||||
assertThat(environment).isInstanceOf(Proxy.class);
|
||||
ResourceLoader resourceLoader = bean.getResourceLoader();
|
||||
assertThat(resourceLoader).isNotInstanceOf(Proxy.class);
|
||||
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
|
||||
assertThat(runtimeHints.proxies().jdkProxies()).singleElement().satisfies(proxyHint ->
|
||||
assertThat(proxyHint.getProxiedInterfaces()).isEqualTo(TypeReference.listOf(
|
||||
environment.getClass().getInterfaces())));
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasLazyAutowiringOnMethod() {
|
||||
testAutowiredComponent(LazyAutowiredMethodComponent.class, (bean, generationContext) -> {
|
||||
Environment environment = bean.getEnvironment();
|
||||
assertThat(environment).isNotInstanceOf(Proxy.class);
|
||||
ResourceLoader resourceLoader = bean.getResourceLoader();
|
||||
assertThat(resourceLoader).isInstanceOf(Proxy.class);
|
||||
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
|
||||
assertThat(runtimeHints.proxies().jdkProxies()).singleElement().satisfies(proxyHint ->
|
||||
assertThat(proxyHint.getProxiedInterfaces()).isEqualTo(TypeReference.listOf(
|
||||
resourceLoader.getClass().getInterfaces())));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasLazyAutowiringOnConstructor() {
|
||||
testAutowiredComponent(LazyConstructorArgumentComponent.class, (bean, generationContext) -> {
|
||||
Environment environment = bean.getEnvironment();
|
||||
assertThat(environment).isInstanceOf(Proxy.class);
|
||||
ResourceLoader resourceLoader = bean.getResourceLoader();
|
||||
assertThat(resourceLoader).isNotInstanceOf(Proxy.class);
|
||||
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
|
||||
assertThat(runtimeHints.proxies().jdkProxies()).singleElement().satisfies(proxyHint ->
|
||||
assertThat(proxyHint.getProxiedInterfaces()).isEqualTo(TypeReference.listOf(
|
||||
environment.getClass().getInterfaces())));
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasLazyAutowiringOnFactoryMethod() {
|
||||
RootBeanDefinition bd = new RootBeanDefinition(LazyFactoryMethodArgumentComponent.class);
|
||||
bd.setFactoryMethodName("of");
|
||||
testAutowiredComponent(LazyFactoryMethodArgumentComponent.class, bd, (bean, generationContext) -> {
|
||||
Environment environment = bean.getEnvironment();
|
||||
assertThat(environment).isInstanceOf(Proxy.class);
|
||||
ResourceLoader resourceLoader = bean.getResourceLoader();
|
||||
assertThat(resourceLoader).isNotInstanceOf(Proxy.class);
|
||||
RuntimeHints runtimeHints = generationContext.getRuntimeHints();
|
||||
assertThat(runtimeHints.proxies().jdkProxies()).singleElement().satisfies(proxyHint ->
|
||||
assertThat(proxyHint.getProxiedInterfaces()).isEqualTo(TypeReference.listOf(
|
||||
environment.getClass().getInterfaces())));
|
||||
});
|
||||
}
|
||||
|
||||
private <T> void testAutowiredComponent(Class<T> type, BiConsumer<T, GenerationContext> assertions) {
|
||||
testAutowiredComponent(type, new RootBeanDefinition(type), assertions);
|
||||
}
|
||||
|
||||
private <T> void testAutowiredComponent(Class<T> type, RootBeanDefinition beanDefinition,
|
||||
BiConsumer<T, GenerationContext> assertions) {
|
||||
GenericApplicationContext applicationContext = new GenericApplicationContext();
|
||||
applicationContext.getDefaultListableBeanFactory().setAutowireCandidateResolver(
|
||||
new ContextAnnotationAutowireCandidateResolver());
|
||||
applicationContext.registerBeanDefinition(AnnotationConfigUtils.AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME,
|
||||
BeanDefinitionBuilder
|
||||
.rootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class)
|
||||
.setRole(BeanDefinition.ROLE_INFRASTRUCTURE).getBeanDefinition());
|
||||
applicationContext.registerBeanDefinition("testComponent", beanDefinition);
|
||||
TestGenerationContext generationContext = processAheadOfTime(applicationContext);
|
||||
testCompiledResult(generationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
assertThat(freshApplicationContext.getBeanDefinitionNames()).containsOnly("testComponent");
|
||||
assertions.accept(freshApplicationContext.getBean("testComponent", type), generationContext);
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenHasInitDestroyMethods() {
|
||||
GenericApplicationContext applicationContext = new GenericApplicationContext();
|
||||
@@ -189,10 +280,14 @@ class ApplicationContextAotGeneratorTests {
|
||||
return generationContext;
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void testCompiledResult(GenericApplicationContext applicationContext,
|
||||
BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) {
|
||||
TestGenerationContext generationContext = processAheadOfTime(applicationContext);
|
||||
testCompiledResult(processAheadOfTime(applicationContext), result);
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
private void testCompiledResult(TestGenerationContext generationContext,
|
||||
BiConsumer<ApplicationContextInitializer<GenericApplicationContext>, Compiled> result) {
|
||||
TestCompiler.forSystem().withFiles(generationContext.getGeneratedFiles()).compile(compiled ->
|
||||
result.accept(compiled.getInstance(ApplicationContextInitializer.class), compiled));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user