Affects: 6.1.3
A bean definition that uses non-common value types like this:
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
RootBeanDefinition beanDefinition = new RootBeanDefinition(MyBean.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(new MyBeanRecord("Bob", 12));
registry.registerBeanDefinition("MyBean", beanDefinition);
}
will cause a ValueCodeGeneration
exception.
Since this use case is intentionally unsupported (see https://github.com/spring-projects/spring-framework/issues/32214#issuecomment-1933482152), a helpful error message saying "ConstructorArgumentValues
do not support code generation for arguments of type (MyBeanRecord)" should be thrown instead, similar to what happens with instance suppliers.
Demo: https://github.com/Christopher-Chianelli/issue-reproducer/tree/constructor-argument-value-unsupported/demo
Comment From: snicoll
It's not really the same thing. The issue you've referenced is a limitation of a supported construct of the core container. Creating a bean definition with an instance supplier is totally supported but, for obvious reasons, can't be supported by the AOT engine.
Providing complex object structure to a BeanDefinition
is not idiomatic at all. The bean definition is an abstraction on top of several models, including our XML namespace where you can't obviously pass such an object. The idiomatic way to provide such object is via factory, or a bean reference.
"ConstructorArgumentValues do not support code generation for arguments of type (MyBeanRecord)" should be thrown instead, similar to https://github.com/spring-projects/spring-framework/issues/29556.
I disagree with that. There's nothing specific with ConstructorArgumentValues
here. That being said, I can see how the ultimate exception thrown at the user can be rephrased by referencing to what I've just explained.
Comment From: snicoll
With the work going on in #32777 this will generate the following:
org.springframework.beans.factory.aot.AotBeanProcessingFailedException: Error processing bean with name 'MyBean': failed to generate code for bean definition
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateRegisterBeanDefinitionsMethod$2(BeanRegistrationsAotContribution.java:101)
at java.base/java.lang.Iterable.forEach(Iterable.java:75)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.generateRegisterBeanDefinitionsMethod(BeanRegistrationsAotContribution.java:88)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$applyTo$1(BeanRegistrationsAotContribution.java:73)
at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.applyTo(BeanRegistrationsAotContribution.java:72)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContributionTests.applyToFailingWrapsValueCodeGeneration2(BeanRegistrationsAotContributionTests.java:205)
at java.base/java.lang.reflect.Method.invoke(Method.java:568)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
Caused by: org.springframework.aot.generate.ValueCodeGenerationException: Failed to generate code for 'MyBeanRecord[name=Bob, age=12]' with type class com.example.MyBeanRecord
at org.springframework.aot.generate.ValueCodeGenerator.generateCode(ValueCodeGenerator.java:116)
at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateValue(BeanDefinitionPropertiesCodeGenerator.java:269)
at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.lambda$addConstructorArgumentValues$3(BeanDefinitionPropertiesCodeGenerator.java:191)
at java.base/java.util.LinkedHashMap.forEach(LinkedHashMap.java:721)
at java.base/java.util.Collections$UnmodifiableMap.forEach(Collections.java:1553)
at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.addConstructorArgumentValues(BeanDefinitionPropertiesCodeGenerator.java:188)
at org.springframework.beans.factory.aot.BeanDefinitionPropertiesCodeGenerator.generateCode(BeanDefinitionPropertiesCodeGenerator.java:134)
at org.springframework.beans.factory.aot.DefaultBeanRegistrationCodeFragments.generateSetBeanDefinitionPropertiesCode(DefaultBeanRegistrationCodeFragments.java:180)
at org.springframework.beans.factory.aot.BeanRegistrationCodeGenerator.generateCode(BeanRegistrationCodeGenerator.java:81)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.lambda$generateBeanDefinitionMethod$3(BeanDefinitionMethodGenerator.java:176)
at org.springframework.aot.generate.GeneratedMethod.<init>(GeneratedMethod.java:54)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:112)
at org.springframework.aot.generate.GeneratedMethods.add(GeneratedMethods.java:89)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:169)
at org.springframework.beans.factory.aot.BeanDefinitionMethodGenerator.generateBeanDefinitionMethod(BeanDefinitionMethodGenerator.java:89)
at org.springframework.beans.factory.aot.BeanRegistrationsAotContribution.lambda$generateRegisterBeanDefinitionsMethod$2(BeanRegistrationsAotContribution.java:91)
... 11 more
Caused by: org.springframework.aot.generate.UnsupportedTypeValueCodeGenerationException: Code generation does not support com.example.MyBeanRecord
at org.springframework.aot.generate.ValueCodeGenerator.generateCode(ValueCodeGenerator.java:113)
... 26 more
Let's rephrase this to have a section in the reference doc that rather explains why this exception is thrown. Conveying that in the exception message is not really practical.