Browse Source

Fix code generation for null indexed argument value

This commit fixes code generation when an indexed constructor argument
value is null as the method is overloaded and need the value to be
cast to `Object`.

Closes gh-31508
pull/31518/head
Stéphane Nicoll 1 year ago
parent
commit
1762bf4a60
  1. 18
      spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java
  2. 16
      spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java

18
spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java

@ -174,7 +174,9 @@ class BeanDefinitionPropertiesCodeGenerator { @@ -174,7 +174,9 @@ class BeanDefinitionPropertiesCodeGenerator {
Map<Integer, ValueHolder> indexedValues = constructorValues.getIndexedArgumentValues();
if (!indexedValues.isEmpty()) {
indexedValues.forEach((index, valueHolder) -> {
CodeBlock valueCode = generateValue(valueHolder.getName(), valueHolder.getValue());
Object value = valueHolder.getValue();
CodeBlock valueCode = castIfNecessary(value == null, Object.class,
generateValue(valueHolder.getName(), value));
code.addStatement(
"$L.getConstructorArgumentValues().addIndexedArgumentValue($L, $L)",
BEAN_DEFINITION_VARIABLE, index, valueCode);
@ -346,6 +348,20 @@ class BeanDefinitionPropertiesCodeGenerator { @@ -346,6 +348,20 @@ class BeanDefinitionPropertiesCodeGenerator {
}
}
/**
* Cast the specified {@code valueCode} to the specified {@code castType} if
* the {@code castNecessary} is {@code true}. Otherwise return the valueCode
* as is.
* @param castNecessary whether a cast is necessary
* @param castType the type to cast to
* @param valueCode the code for the value
* @return the existing value or a form of {@code (CastType) valueCode} if a
* cast is necessary
*/
private CodeBlock castIfNecessary(boolean castNecessary, Class<?> castType, CodeBlock valueCode) {
return (castNecessary ? CodeBlock.of("($T) $L", castType, valueCode) : valueCode);
}
static class PropertyNamesStack {
private static final ThreadLocal<ArrayDeque<String>> threadLocal = ThreadLocal.withInitial(ArrayDeque::new);

16
spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java

@ -235,6 +235,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -235,6 +235,18 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
});
}
@Test
void constructorArgumentValuesWhenIndexedNullValue() {
this.beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, (Object) null);
compile((actual, compiled) -> {
ConstructorArgumentValues argumentValues = actual.getConstructorArgumentValues();
Map<Integer, ValueHolder> values = argumentValues.getIndexedArgumentValues();
assertThat(values.get(0)).satisfies(assertValueHolder(null, null, null));
assertThat(values).hasSize(1);
assertThat(argumentValues.getGenericArgumentValues()).isEmpty();
});
}
@Test
void constructorArgumentValuesWhenGenericValuesWithName() {
this.beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(String.class);
@ -255,7 +267,9 @@ class BeanDefinitionPropertiesCodeGeneratorTests { @@ -255,7 +267,9 @@ class BeanDefinitionPropertiesCodeGeneratorTests {
});
}
private Consumer<ValueHolder> assertValueHolder(Object value, @Nullable Class<?> type, @Nullable String name) {
private Consumer<ValueHolder> assertValueHolder(
@Nullable Object value, @Nullable Class<?> type, @Nullable String name) {
return valueHolder -> {
assertThat(valueHolder.getValue()).isEqualTo(value);
assertThat(valueHolder.getType()).isEqualTo((type != null ? type.getName() : null));

Loading…
Cancel
Save