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:
parent
ca4d0d784b
commit
85388aa642
|
|
@ -24,6 +24,7 @@ import java.util.Arrays;
|
|||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
|
@ -43,6 +44,7 @@ import org.springframework.beans.PropertyValue;
|
|||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.AutowireCandidateQualifier;
|
||||
|
|
@ -168,16 +170,38 @@ class BeanDefinitionPropertiesCodeGenerator {
|
|||
}
|
||||
|
||||
private void addConstructorArgumentValues(CodeBlock.Builder code, BeanDefinition beanDefinition) {
|
||||
Map<Integer, ValueHolder> argumentValues =
|
||||
beanDefinition.getConstructorArgumentValues().getIndexedArgumentValues();
|
||||
if (!argumentValues.isEmpty()) {
|
||||
argumentValues.forEach((index, valueHolder) -> {
|
||||
ConstructorArgumentValues constructorValues = beanDefinition.getConstructorArgumentValues();
|
||||
Map<Integer, ValueHolder> indexedValues = constructorValues.getIndexedArgumentValues();
|
||||
if (!indexedValues.isEmpty()) {
|
||||
indexedValues.forEach((index, valueHolder) -> {
|
||||
CodeBlock valueCode = generateValue(valueHolder.getName(), valueHolder.getValue());
|
||||
code.addStatement(
|
||||
"$L.getConstructorArgumentValues().addIndexedArgumentValue($L, $L)",
|
||||
BEAN_DEFINITION_VARIABLE, index, valueCode);
|
||||
});
|
||||
}
|
||||
List<ValueHolder> genericValues = constructorValues.getGenericArgumentValues();
|
||||
if (!genericValues.isEmpty()) {
|
||||
genericValues.forEach(valueHolder -> {
|
||||
String valueName = valueHolder.getName();
|
||||
CodeBlock valueCode = generateValue(valueName, valueHolder.getValue());
|
||||
if (valueName != null) {
|
||||
CodeBlock valueTypeCode = this.valueCodeGenerator.generateCode(valueHolder.getType());
|
||||
code.addStatement(
|
||||
"$L.getConstructorArgumentValues().addGenericArgumentValue(new $T($L, $L, $S))",
|
||||
BEAN_DEFINITION_VARIABLE, ValueHolder.class, valueCode, valueTypeCode, valueName);
|
||||
}
|
||||
else if (valueHolder.getType() != null) {
|
||||
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L, $S)",
|
||||
BEAN_DEFINITION_VARIABLE, valueCode, valueHolder.getType());
|
||||
|
||||
}
|
||||
else {
|
||||
code.addStatement("$L.getConstructorArgumentValues().addGenericArgumentValue($L)",
|
||||
BEAN_DEFINITION_VARIABLE, valueCode);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void addPropertyValues(CodeBlock.Builder code, RootBeanDefinition beanDefinition) {
|
||||
|
|
|
|||
|
|
@ -20,8 +20,11 @@ import java.lang.reflect.Constructor;
|
|||
import java.lang.reflect.Executable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
|
@ -248,7 +251,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
Assert.isTrue(this.shortcuts == null || this.shortcuts.length == resolved.length,
|
||||
() -> "'shortcuts' must contain " + resolved.length + " elements");
|
||||
|
||||
ConstructorArgumentValues argumentValues = resolveArgumentValues(registeredBean);
|
||||
ValueHolder[] argumentValues = resolveArgumentValues(registeredBean, executable);
|
||||
Set<String> autowiredBeanNames = new LinkedHashSet<>(resolved.length * 2);
|
||||
for (int i = startIndex; i < parameterCount; i++) {
|
||||
MethodParameter parameter = getMethodParameter(executable, i);
|
||||
|
|
@ -257,8 +260,9 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
if (shortcut != null) {
|
||||
descriptor = new ShortcutDependencyDescriptor(descriptor, shortcut);
|
||||
}
|
||||
ValueHolder argumentValue = argumentValues.getIndexedArgumentValue(i, null);
|
||||
resolved[i - startIndex] = resolveArgument(registeredBean, descriptor, argumentValue, autowiredBeanNames);
|
||||
ValueHolder argumentValue = argumentValues[i];
|
||||
resolved[i - startIndex] = resolveAutowiredArgument(
|
||||
registeredBean, descriptor, argumentValue, autowiredBeanNames);
|
||||
}
|
||||
registerDependentBeans(registeredBean.getBeanFactory(), registeredBean.getBeanName(), autowiredBeanNames);
|
||||
|
||||
|
|
@ -275,22 +279,44 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
throw new IllegalStateException("Unsupported executable: " + executable.getClass().getName());
|
||||
}
|
||||
|
||||
private ConstructorArgumentValues resolveArgumentValues(RegisteredBean registeredBean) {
|
||||
ConstructorArgumentValues resolved = new ConstructorArgumentValues();
|
||||
private ValueHolder[] resolveArgumentValues(RegisteredBean registeredBean, Executable executable) {
|
||||
Parameter[] parameters = executable.getParameters();
|
||||
ValueHolder[] resolved = new ValueHolder[parameters.length];
|
||||
RootBeanDefinition beanDefinition = registeredBean.getMergedBeanDefinition();
|
||||
if (beanDefinition.hasConstructorArgumentValues() &&
|
||||
registeredBean.getBeanFactory() instanceof AbstractAutowireCapableBeanFactory beanFactory) {
|
||||
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(
|
||||
beanFactory, registeredBean.getBeanName(), beanDefinition, beanFactory.getTypeConverter());
|
||||
ConstructorArgumentValues values = beanDefinition.getConstructorArgumentValues();
|
||||
values.getIndexedArgumentValues().forEach((index, valueHolder) -> {
|
||||
ValueHolder resolvedValue = resolveArgumentValue(valueResolver, valueHolder);
|
||||
resolved.addIndexedArgumentValue(index, resolvedValue);
|
||||
});
|
||||
ConstructorArgumentValues values = resolveConstructorArguments(
|
||||
valueResolver, beanDefinition.getConstructorArgumentValues());
|
||||
Set<ValueHolder> usedValueHolders = new HashSet<>(parameters.length);
|
||||
for (int i = 0; i < parameters.length; i++) {
|
||||
Class<?> parameterType = parameters[i].getType();
|
||||
String parameterName = (parameters[i].isNamePresent() ? parameters[i].getName() : null);
|
||||
ValueHolder valueHolder = values.getArgumentValue(
|
||||
i, parameterType, parameterName, usedValueHolders);
|
||||
if (valueHolder != null) {
|
||||
resolved[i] = valueHolder;
|
||||
usedValueHolders.add(valueHolder);
|
||||
}
|
||||
}
|
||||
}
|
||||
return resolved;
|
||||
}
|
||||
|
||||
private ConstructorArgumentValues resolveConstructorArguments(
|
||||
BeanDefinitionValueResolver valueResolver, ConstructorArgumentValues constructorArguments) {
|
||||
|
||||
ConstructorArgumentValues resolvedConstructorArguments = new ConstructorArgumentValues();
|
||||
for (Map.Entry<Integer, ConstructorArgumentValues.ValueHolder> entry : constructorArguments.getIndexedArgumentValues().entrySet()) {
|
||||
resolvedConstructorArguments.addIndexedArgumentValue(entry.getKey(), resolveArgumentValue(valueResolver, entry.getValue()));
|
||||
}
|
||||
for (ConstructorArgumentValues.ValueHolder valueHolder : constructorArguments.getGenericArgumentValues()) {
|
||||
resolvedConstructorArguments.addGenericArgumentValue(resolveArgumentValue(valueResolver, valueHolder));
|
||||
}
|
||||
return resolvedConstructorArguments;
|
||||
}
|
||||
|
||||
private ValueHolder resolveArgumentValue(BeanDefinitionValueResolver resolver, ValueHolder valueHolder) {
|
||||
if (valueHolder.isConverted()) {
|
||||
return valueHolder;
|
||||
|
|
@ -302,7 +328,7 @@ public final class BeanInstanceSupplier<T> extends AutowiredElementResolver impl
|
|||
}
|
||||
|
||||
@Nullable
|
||||
private Object resolveArgument(RegisteredBean registeredBean, DependencyDescriptor descriptor,
|
||||
private Object resolveAutowiredArgument(RegisteredBean registeredBean, DependencyDescriptor descriptor,
|
||||
@Nullable ValueHolder argumentValue, Set<String> autowiredBeanNames) {
|
||||
|
||||
TypeConverter typeConverter = registeredBean.getBeanFactory().getTypeConverter();
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
|||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.DependencyDescriptor;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.core.CollectionFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.NamedThreadLocal;
|
||||
|
|
@ -999,6 +1000,9 @@ class ConstructorResolver {
|
|||
for (ValueHolder valueHolder : mbd.getConstructorArgumentValues().getIndexedArgumentValues().values()) {
|
||||
parameterTypes.add(determineParameterValueType(mbd, valueHolder));
|
||||
}
|
||||
for (ValueHolder valueHolder : mbd.getConstructorArgumentValues().getGenericArgumentValues()) {
|
||||
parameterTypes.add(determineParameterValueType(mbd, valueHolder));
|
||||
}
|
||||
return parameterTypes;
|
||||
}
|
||||
|
||||
|
|
@ -1023,6 +1027,12 @@ class ConstructorResolver {
|
|||
return (FactoryBean.class.isAssignableFrom(type.toClass()) ?
|
||||
type.as(FactoryBean.class).getGeneric(0) : type);
|
||||
}
|
||||
if (value instanceof TypedStringValue typedValue) {
|
||||
if (typedValue.hasTargetType()) {
|
||||
return ResolvableType.forClass(typedValue.getTargetType());
|
||||
}
|
||||
return ResolvableType.forClass(String.class);
|
||||
}
|
||||
if (value instanceof Class<?> clazz) {
|
||||
return ResolvableType.forClassWithGenerics(Class.class, clazz);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import org.springframework.aot.test.generate.TestGenerationContext;
|
|||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues;
|
||||
import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanNameReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
|
|
@ -219,18 +220,49 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void constructorArgumentValuesWhenValues() {
|
||||
void constructorArgumentValuesWhenIndexedValues() {
|
||||
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, String.class);
|
||||
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(1, "test");
|
||||
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(2, 123);
|
||||
compile((actual, compiled) -> {
|
||||
Map<Integer, ValueHolder> values = actual.getConstructorArgumentValues().getIndexedArgumentValues();
|
||||
assertThat(values.get(0).getValue()).isEqualTo(String.class);
|
||||
assertThat(values.get(1).getValue()).isEqualTo("test");
|
||||
assertThat(values.get(2).getValue()).isEqualTo(123);
|
||||
ConstructorArgumentValues argumentValues = actual.getConstructorArgumentValues();
|
||||
Map<Integer, ValueHolder> values = argumentValues.getIndexedArgumentValues();
|
||||
assertThat(values.get(0)).satisfies(assertValueHolder(String.class, null, null));
|
||||
assertThat(values.get(1)).satisfies(assertValueHolder("test", null, null));
|
||||
assertThat(values.get(2)).satisfies(assertValueHolder(123, null, null));
|
||||
assertThat(values).hasSize(3);
|
||||
assertThat(argumentValues.getGenericArgumentValues()).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void constructorArgumentValuesWhenGenericValuesWithName() {
|
||||
this.beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(String.class);
|
||||
this.beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(2, Long.class.getName());
|
||||
this.beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
|
||||
new ValueHolder("value", null, "param1"));
|
||||
this.beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
|
||||
new ValueHolder("another", CharSequence.class.getName(), "param2"));
|
||||
compile((actual, compiled) -> {
|
||||
ConstructorArgumentValues argumentValues = actual.getConstructorArgumentValues();
|
||||
List<ValueHolder> values = argumentValues.getGenericArgumentValues();
|
||||
assertThat(values.get(0)).satisfies(assertValueHolder(String.class, null, null));
|
||||
assertThat(values.get(1)).satisfies(assertValueHolder(2, Long.class, null));
|
||||
assertThat(values.get(2)).satisfies(assertValueHolder("value", null, "param1"));
|
||||
assertThat(values.get(3)).satisfies(assertValueHolder("another", CharSequence.class, "param2"));
|
||||
assertThat(values).hasSize(4);
|
||||
assertThat(argumentValues.getIndexedArgumentValues()).isEmpty();
|
||||
});
|
||||
}
|
||||
|
||||
private Consumer<ValueHolder> assertValueHolder(Object value, @Nullable Class<?> type, @Nullable String name) {
|
||||
return valueHolder -> {
|
||||
assertThat(valueHolder.getValue()).isEqualTo(value);
|
||||
assertThat(valueHolder.getType()).isEqualTo((type != null ? type.getName() : null));
|
||||
assertThat(valueHolder.getName()).isEqualTo(name);
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
void propertyValuesWhenValues() {
|
||||
this.beanDefinition.setTargetType(PropertyValuesBean.class);
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ class BeanInstanceSupplierTests {
|
|||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.MIXED_ARGS)
|
||||
void resolveArgumentsWithMixedArgsConstructorWithUserValue(Source source) {
|
||||
void resolveArgumentsWithMixedArgsConstructorWithIndexedUserValue(Source source) {
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
Environment environment = mock();
|
||||
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
|
||||
|
|
@ -465,7 +465,28 @@ class BeanInstanceSupplierTests {
|
|||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.MIXED_ARGS)
|
||||
void resolveArgumentsWithMixedArgsConstructorWithUserBeanReference(Source source) {
|
||||
void resolveArgumentsWithMixedArgsConstructorWithGenericUserValue(Source source) {
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
Environment environment = mock();
|
||||
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
|
||||
resourceLoader);
|
||||
this.beanFactory.registerSingleton("environment", environment);
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> {
|
||||
beanDefinition
|
||||
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue("user-value");
|
||||
});
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(3);
|
||||
assertThat(arguments.getObject(0)).isEqualTo(resourceLoader);
|
||||
assertThat(arguments.getObject(1)).isEqualTo("user-value");
|
||||
assertThat(arguments.getObject(2)).isEqualTo(environment);
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.MIXED_ARGS)
|
||||
void resolveArgumentsWithMixedArgsConstructorAndIndexedUserBeanReference(Source source) {
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
Environment environment = mock();
|
||||
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
|
||||
|
|
@ -487,8 +508,31 @@ class BeanInstanceSupplierTests {
|
|||
assertThat(arguments.getObject(2)).isEqualTo(environment);
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.MIXED_ARGS)
|
||||
void resolveArgumentsWithMixedArgsConstructorAndGenericUserBeanReference(Source source) {
|
||||
ResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
Environment environment = mock();
|
||||
this.beanFactory.registerResolvableDependency(ResourceLoader.class,
|
||||
resourceLoader);
|
||||
this.beanFactory.registerSingleton("environment", environment);
|
||||
this.beanFactory.registerSingleton("one", "1");
|
||||
this.beanFactory.registerSingleton("two", "2");
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> {
|
||||
beanDefinition
|
||||
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(new RuntimeBeanReference("two"));
|
||||
});
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(3);
|
||||
assertThat(arguments.getObject(0)).isEqualTo(resourceLoader);
|
||||
assertThat(arguments.getObject(1)).isEqualTo("2");
|
||||
assertThat(arguments.getObject(2)).isEqualTo(environment);
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveArgumentsWithUserValueWithTypeConversionRequired() {
|
||||
void resolveIndexedArgumentsWithUserValueWithTypeConversionRequired() {
|
||||
Source source = new Source(CharDependency.class,
|
||||
BeanInstanceSupplier.forConstructor(char.class));
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
|
|
@ -503,8 +547,24 @@ class BeanInstanceSupplierTests {
|
|||
assertThat(arguments.getObject(0)).isInstanceOf(Character.class).isEqualTo('\\');
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveGenericArgumentsWithUserValueWithTypeConversionRequired() {
|
||||
Source source = new Source(CharDependency.class,
|
||||
BeanInstanceSupplier.forConstructor(char.class));
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> {
|
||||
beanDefinition
|
||||
.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_CONSTRUCTOR);
|
||||
beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue("\\", char.class.getName());
|
||||
});
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(1);
|
||||
assertThat(arguments.getObject(0)).isInstanceOf(Character.class).isEqualTo('\\');
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveArgumentsWithUserValueWithBeanReference(Source source) {
|
||||
void resolveIndexedArgumentsWithUserValueWithBeanReference(Source source) {
|
||||
this.beanFactory.registerSingleton("stringBean", "string");
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> beanDefinition.getConstructorArgumentValues()
|
||||
|
|
@ -516,7 +576,18 @@ class BeanInstanceSupplierTests {
|
|||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveArgumentsWithUserValueWithBeanDefinition(Source source) {
|
||||
void resolveGenericArgumentsWithUserValueWithBeanReference(Source source) {
|
||||
this.beanFactory.registerSingleton("stringBean", "string");
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(new RuntimeBeanReference("stringBean")));
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(1);
|
||||
assertThat(arguments.getObject(0)).isEqualTo("string");
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveIndexedArgumentsWithUserValueWithBeanDefinition(Source source) {
|
||||
AbstractBeanDefinition userValue = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(String.class, () -> "string").getBeanDefinition();
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
|
|
@ -528,11 +599,23 @@ class BeanInstanceSupplierTests {
|
|||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveArgumentsWithUserValueThatIsAlreadyResolved(Source source) {
|
||||
void resolveGenericArgumentsWithUserValueWithBeanDefinition(Source source) {
|
||||
AbstractBeanDefinition userValue = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(String.class, () -> "string").getBeanDefinition();
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory,
|
||||
beanDefinition -> beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(userValue));
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(1);
|
||||
assertThat(arguments.getObject(0)).isEqualTo("string");
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveIndexedArgumentsWithUserValueThatIsAlreadyResolved(Source source) {
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory);
|
||||
BeanDefinition mergedBeanDefinition = this.beanFactory
|
||||
.getMergedBeanDefinition("testBean");
|
||||
ValueHolder valueHolder = new ValueHolder('a');
|
||||
ValueHolder valueHolder = new ValueHolder("a");
|
||||
valueHolder.setConvertedValue("this is an a");
|
||||
mergedBeanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0,
|
||||
valueHolder);
|
||||
|
|
@ -541,6 +624,19 @@ class BeanInstanceSupplierTests {
|
|||
assertThat(arguments.getObject(0)).isEqualTo("this is an a");
|
||||
}
|
||||
|
||||
@ParameterizedResolverTest(Sources.SINGLE_ARG)
|
||||
void resolveGenericArgumentsWithUserValueThatIsAlreadyResolved(Source source) {
|
||||
RegisteredBean registerBean = source.registerBean(this.beanFactory);
|
||||
BeanDefinition mergedBeanDefinition = this.beanFactory
|
||||
.getMergedBeanDefinition("testBean");
|
||||
ValueHolder valueHolder = new ValueHolder("a");
|
||||
valueHolder.setConvertedValue("this is an a");
|
||||
mergedBeanDefinition.getConstructorArgumentValues().addGenericArgumentValue(valueHolder);
|
||||
AutowiredArguments arguments = source.getResolver().resolveArguments(registerBean);
|
||||
assertThat(arguments.toArray()).hasSize(1);
|
||||
assertThat(arguments.getObject(0)).isEqualTo("this is an a");
|
||||
}
|
||||
|
||||
@Test
|
||||
void resolveArgumentsWhenUsingShortcutsInjectsDirectly() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory() {
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import org.junit.jupiter.api.Test;
|
|||
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.TypedStringValue;
|
||||
import org.springframework.beans.testfixture.beans.factory.generator.factory.NumberHolder;
|
||||
import org.springframework.beans.testfixture.beans.factory.generator.factory.NumberHolderFactoryBean;
|
||||
import org.springframework.beans.testfixture.beans.factory.generator.factory.SampleFactory;
|
||||
|
|
@ -72,7 +73,7 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithFactoryMethodNameAndAssignableConstructorArg() {
|
||||
void beanDefinitionWithFactoryMethodNameAndAssignableIndexedConstructorArgs() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerSingleton("testNumber", 1L);
|
||||
beanFactory.registerSingleton("testBean", "test");
|
||||
|
|
@ -85,6 +86,34 @@ class ConstructorResolverAotTests {
|
|||
.findMethod(SampleFactory.class, "create", Number.class, String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithFactoryMethodNameAndAssignableGenericConstructorArgs() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SampleFactory.class).setFactoryMethod("create")
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("test");
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(1L);
|
||||
Executable executable = resolve(beanFactory, beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(ReflectionUtils
|
||||
.findMethod(SampleFactory.class, "create", Number.class, String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithFactoryMethodNameAndAssignableTypeStringValues() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SampleFactory.class).setFactoryMethod("create")
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(new TypedStringValue("test"));
|
||||
beanDefinition.getConstructorArgumentValues()
|
||||
.addGenericArgumentValue(new TypedStringValue("1", Integer.class));
|
||||
Executable executable = resolve(beanFactory, beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(ReflectionUtils
|
||||
.findMethod(SampleFactory.class, "create", Number.class, String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithFactoryMethodNameAndMatchingMethodNames() {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
|
|
@ -122,7 +151,7 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithConstructorArgsForMultipleConstructors() throws Exception {
|
||||
void beanDefinitionWithIndexedConstructorArgsForMultipleConstructors() throws Exception {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerSingleton("testNumber", 1L);
|
||||
beanFactory.registerSingleton("testBean", "test");
|
||||
|
|
@ -136,7 +165,22 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingValue() throws NoSuchMethodException {
|
||||
void beanDefinitionWithGenericConstructorArgsForMultipleConstructors() throws Exception {
|
||||
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
|
||||
beanFactory.registerSingleton("testNumber", 1L);
|
||||
beanFactory.registerSingleton("testBean", "test");
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(SampleBeanWithConstructors.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue("test");
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(1L);
|
||||
Executable executable = resolve(beanFactory, beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(SampleBeanWithConstructors.class
|
||||
.getDeclaredConstructor(Number.class, String.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingIndexedValue() throws NoSuchMethodException {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.addConstructorArgValue(42).getBeanDefinition();
|
||||
|
|
@ -146,7 +190,18 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingArrayValue() throws NoSuchMethodException {
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingGenericValue() throws NoSuchMethodException {
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(42);
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(
|
||||
MultiConstructorSample.class.getDeclaredConstructor(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingArrayFromIndexedValue() throws NoSuchMethodException {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorArraySample.class)
|
||||
.addConstructorArgValue(42).getBeanDefinition();
|
||||
|
|
@ -156,7 +211,18 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingListValue() throws NoSuchMethodException {
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingArrayFromGenericValue() throws NoSuchMethodException {
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorArraySample.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(42);
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(MultiConstructorArraySample.class
|
||||
.getDeclaredConstructor(Integer[].class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingListFromIndexedValue() throws NoSuchMethodException {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorListSample.class)
|
||||
.addConstructorArgValue(42).getBeanDefinition();
|
||||
|
|
@ -166,7 +232,18 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBean() throws NoSuchMethodException {
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingListFromGenericValue() throws NoSuchMethodException {
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorListSample.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(42);
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(
|
||||
MultiConstructorListSample.class.getDeclaredConstructor(List.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingIndexedValueAsInnerBean() throws NoSuchMethodException {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.addConstructorArgValue(
|
||||
|
|
@ -179,7 +256,20 @@ class ConstructorResolverAotTests {
|
|||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingValueAsInnerBeanFactory() throws NoSuchMethodException {
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingGenericValueAsInnerBean() throws NoSuchMethodException {
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
|
||||
BeanDefinitionBuilder.rootBeanDefinition(Integer.class, "valueOf")
|
||||
.addConstructorArgValue("42").getBeanDefinition());
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(
|
||||
MultiConstructorSample.class.getDeclaredConstructor(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingIndexedValueAsInnerBeanFactory() throws NoSuchMethodException {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.addConstructorArgValue(BeanDefinitionBuilder
|
||||
|
|
@ -190,6 +280,18 @@ class ConstructorResolverAotTests {
|
|||
MultiConstructorSample.class.getDeclaredConstructor(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndMatchingGenericValueAsInnerBeanFactory() throws NoSuchMethodException {
|
||||
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
.rootBeanDefinition(MultiConstructorSample.class)
|
||||
.getBeanDefinition();
|
||||
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(
|
||||
BeanDefinitionBuilder.rootBeanDefinition(IntegerFactoryBean.class).getBeanDefinition());
|
||||
Executable executable = resolve(new DefaultListableBeanFactory(), beanDefinition);
|
||||
assertThat(executable).isNotNull().isEqualTo(
|
||||
MultiConstructorSample.class.getDeclaredConstructor(Integer.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
void beanDefinitionWithMultiArgConstructorAndNonMatchingValue() {
|
||||
BeanDefinition beanDefinition = BeanDefinitionBuilder
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import org.apache.commons.logging.LogFactory;
|
|||
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanDefinitionHolder;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
|
|
@ -479,26 +480,32 @@ final class PostProcessorRegistrationDelegate {
|
|||
BeanDefinitionValueResolver valueResolver = new BeanDefinitionValueResolver(this.beanFactory, beanName, bd);
|
||||
postProcessors.forEach(postProcessor -> postProcessor.postProcessMergedBeanDefinition(bd, beanType, beanName));
|
||||
for (PropertyValue propertyValue : bd.getPropertyValues().getPropertyValueList()) {
|
||||
Object value = propertyValue.getValue();
|
||||
if (value instanceof AbstractBeanDefinition innerBd) {
|
||||
Class<?> innerBeanType = resolveBeanType(innerBd);
|
||||
resolveInnerBeanDefinition(valueResolver, innerBd, (innerBeanName, innerBeanDefinition)
|
||||
-> postProcessRootBeanDefinition(postProcessors, innerBeanName, innerBeanType, innerBeanDefinition));
|
||||
}
|
||||
if (value instanceof TypedStringValue typedStringValue) {
|
||||
resolveTypeStringValue(typedStringValue);
|
||||
}
|
||||
postProcessValue(postProcessors, valueResolver, propertyValue.getValue());
|
||||
}
|
||||
for (ValueHolder valueHolder : bd.getConstructorArgumentValues().getIndexedArgumentValues().values()) {
|
||||
Object value = valueHolder.getValue();
|
||||
if (value instanceof AbstractBeanDefinition innerBd) {
|
||||
postProcessValue(postProcessors, valueResolver, valueHolder.getValue());
|
||||
}
|
||||
for (ValueHolder valueHolder : bd.getConstructorArgumentValues().getGenericArgumentValues()) {
|
||||
postProcessValue(postProcessors, valueResolver, valueHolder.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
private void postProcessValue(List<MergedBeanDefinitionPostProcessor> postProcessors,
|
||||
BeanDefinitionValueResolver valueResolver, @Nullable Object value) {
|
||||
if (value instanceof BeanDefinitionHolder bdh
|
||||
&& bdh.getBeanDefinition() instanceof AbstractBeanDefinition innerBd) {
|
||||
|
||||
Class<?> innerBeanType = resolveBeanType(innerBd);
|
||||
resolveInnerBeanDefinition(valueResolver, innerBd, (innerBeanName, innerBeanDefinition)
|
||||
-> postProcessRootBeanDefinition(postProcessors, innerBeanName, innerBeanType, innerBeanDefinition));
|
||||
}
|
||||
if (value instanceof TypedStringValue typedStringValue) {
|
||||
resolveTypeStringValue(typedStringValue);
|
||||
else if (value instanceof AbstractBeanDefinition innerBd) {
|
||||
Class<?> innerBeanType = resolveBeanType(innerBd);
|
||||
resolveInnerBeanDefinition(valueResolver, innerBd, (innerBeanName, innerBeanDefinition)
|
||||
-> postProcessRootBeanDefinition(postProcessors, innerBeanName, innerBeanType, innerBeanDefinition));
|
||||
}
|
||||
else if (value instanceof TypedStringValue typedStringValue) {
|
||||
resolveTypeStringValue(typedStringValue);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="petInnerBean" class="org.springframework.beans.testfixture.beans.Pet">
|
||||
<constructor-arg>
|
||||
<bean class="java.lang.String">
|
||||
<constructor-arg value="Fido"/>
|
||||
</bean>
|
||||
</constructor-arg>
|
||||
</bean>
|
||||
|
||||
<bean id="petName" class="java.lang.String">
|
||||
<constructor-arg value="Dofi"/>
|
||||
</bean>
|
||||
|
||||
<bean id="petRefBean" class="org.springframework.beans.testfixture.beans.Pet">
|
||||
<constructor-arg ref="petName"/>
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
@ -8,8 +8,12 @@
|
|||
<property name="company" value="Acme Widgets, Inc." />
|
||||
</bean>
|
||||
|
||||
<bean id="pet" class="org.springframework.beans.testfixture.beans.Pet">
|
||||
<bean id="petIndexed" class="org.springframework.beans.testfixture.beans.Pet">
|
||||
<constructor-arg index="0" value="Fido" />
|
||||
</bean>
|
||||
|
||||
<bean id="petGeneric" class="org.springframework.beans.testfixture.beans.Pet">
|
||||
<constructor-arg value="Dofi" />
|
||||
</bean>
|
||||
|
||||
</beans>
|
||||
|
|
|
|||
Loading…
Reference in New Issue