Add AOT support for generic constructor argument values
This commit improves compatibility with the core container when running in AOT mode by adding support for generic constructor argument values. Previously, these were ignored altogether. We now have code generation support for them as well as resolution that is similar to what AbstractAutowiredCapableBeanFactory does in a regular runtime. This commit also improves AOT support for XML bean configurations by adding more support for TypedStringValue and inner bean definitions. Closes gh-31420
This commit is contained in:
@@ -459,8 +459,10 @@ class ApplicationContextAotGeneratorTests {
|
||||
assertThat(employee.getName()).isEqualTo("John Smith");
|
||||
assertThat(employee.getAge()).isEqualTo(42);
|
||||
assertThat(employee.getCompany()).isEqualTo("Acme Widgets, Inc.");
|
||||
assertThat(freshApplicationContext.getBean("pet", Pet.class)
|
||||
assertThat(freshApplicationContext.getBean("petIndexed", Pet.class)
|
||||
.getName()).isEqualTo("Fido");
|
||||
assertThat(freshApplicationContext.getBean("petGeneric", Pet.class)
|
||||
.getName()).isEqualTo("Dofi");
|
||||
});
|
||||
}
|
||||
|
||||
@@ -496,6 +498,20 @@ class ApplicationContextAotGeneratorTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void processAheadOfTimeWhenXmlHasBeanReferences() {
|
||||
GenericXmlApplicationContext applicationContext = new GenericXmlApplicationContext();
|
||||
applicationContext
|
||||
.load(new ClassPathResource("applicationContextAotGeneratorTests-references.xml", getClass()));
|
||||
testCompiledResult(applicationContext, (initializer, compiled) -> {
|
||||
GenericApplicationContext freshApplicationContext = toFreshApplicationContext(initializer);
|
||||
assertThat(freshApplicationContext.getBean("petInnerBean", Pet.class)
|
||||
.getName()).isEqualTo("Fido");
|
||||
assertThat(freshApplicationContext.getBean("petRefBean", Pet.class)
|
||||
.getName()).isEqualTo("Dofi");
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private Consumer<List<? extends JdkProxyHint>> doesNotHaveProxyFor(Class<?> target) {
|
||||
|
||||
@@ -331,7 +331,7 @@ class GenericApplicationContextTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotLoadsBeanClassNameOfConstructorArgumentInnerBeanDefinition() {
|
||||
void refreshForAotLoadsBeanClassNameOfIndexedConstructorArgumentInnerBeanDefinition() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||
GenericBeanDefinition innerBeanDefinition = new GenericBeanDefinition();
|
||||
@@ -347,6 +347,23 @@ class GenericApplicationContextTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotLoadsBeanClassNameOfGenericConstructorArgumentInnerBeanDefinition() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(String.class);
|
||||
GenericBeanDefinition innerBeanDefinition = new GenericBeanDefinition();
|
||||
innerBeanDefinition.setBeanClassName("java.lang.Integer");
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(innerBeanDefinition);
|
||||
context.registerBeanDefinition("test",beanDefinition);
|
||||
context.refreshForAotProcessing(new RuntimeHints());
|
||||
RootBeanDefinition bd = getBeanDefinition(context, "test");
|
||||
GenericBeanDefinition value = (GenericBeanDefinition) bd.getConstructorArgumentValues()
|
||||
.getGenericArgumentValues().get(0).getValue();
|
||||
assertThat(value.hasBeanClass()).isTrue();
|
||||
assertThat(value.getBeanClass()).isEqualTo(Integer.class);
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotLoadsBeanClassNameOfPropertyValueInnerBeanDefinition() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
@@ -377,7 +394,7 @@ class GenericApplicationContextTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotLoadsTypedStringValueClassNameInConstructorArgument() {
|
||||
void refreshForAotLoadsTypedStringValueClassNameInIndexedConstructorArgument() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition("java.lang.Integer");
|
||||
beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
|
||||
@@ -391,6 +408,21 @@ class GenericApplicationContextTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotLoadsTypedStringValueClassNameInGenericConstructorArgument() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition("java.lang.Integer");
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
|
||||
new TypedStringValue("42", "java.lang.Integer"));
|
||||
context.registerBeanDefinition("number", beanDefinition);
|
||||
context.refreshForAotProcessing(new RuntimeHints());
|
||||
assertThat(getBeanDefinition(context, "number").getConstructorArgumentValues()
|
||||
.getGenericArgumentValue(TypedStringValue.class).getValue())
|
||||
.isInstanceOfSatisfying(TypedStringValue.class, typeStringValue ->
|
||||
assertThat(typeStringValue.getTargetType()).isEqualTo(Integer.class));
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotInvokesBeanFactoryPostProcessors() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
@@ -414,7 +446,7 @@ class GenericApplicationContextTests {
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotInvokesMergedBeanDefinitionPostProcessorsOnConstructorArgument() {
|
||||
void refreshForAotInvokesMergedBeanDefinitionPostProcessorsOnIndexedConstructorArgument() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(BeanD.class);
|
||||
GenericBeanDefinition innerBeanDefinition = new GenericBeanDefinition();
|
||||
@@ -430,6 +462,23 @@ class GenericApplicationContextTests {
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotInvokesMergedBeanDefinitionPostProcessorsOnGenericConstructorArgument() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
RootBeanDefinition beanDefinition = new RootBeanDefinition(BeanD.class);
|
||||
GenericBeanDefinition innerBeanDefinition = new GenericBeanDefinition();
|
||||
innerBeanDefinition.setBeanClassName("java.lang.Integer");
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(innerBeanDefinition);
|
||||
context.registerBeanDefinition("test", beanDefinition);
|
||||
MergedBeanDefinitionPostProcessor bpp = registerMockMergedBeanDefinitionPostProcessor(context);
|
||||
context.refreshForAotProcessing(new RuntimeHints());
|
||||
ArgumentCaptor<String> captor = ArgumentCaptor.forClass(String.class);
|
||||
verify(bpp).postProcessMergedBeanDefinition(getBeanDefinition(context, "test"), BeanD.class, "test");
|
||||
verify(bpp).postProcessMergedBeanDefinition(any(RootBeanDefinition.class), eq(Integer.class), captor.capture());
|
||||
assertThat(captor.getValue()).startsWith("(inner bean)");
|
||||
context.close();
|
||||
}
|
||||
|
||||
@Test
|
||||
void refreshForAotInvokesMergedBeanDefinitionPostProcessorsOnPropertyValue() {
|
||||
GenericApplicationContext context = new GenericApplicationContext();
|
||||
|
||||
Reference in New Issue
Block a user