diff --git a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java index 6ebf25cc4e..b37d599bca 100644 --- a/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java +++ b/spring-beans/src/main/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGenerator.java @@ -40,6 +40,7 @@ import org.springframework.beans.BeanInfoFactory; import org.springframework.beans.ExtendedBeanInfoFactory; import org.springframework.beans.MutablePropertyValues; 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.ValueHolder; @@ -173,7 +174,7 @@ class BeanDefinitionPropertiesCodeGenerator { } private void addPropertyValues(CodeBlock.Builder builder, - BeanDefinition beanDefinition) { + RootBeanDefinition beanDefinition) { MutablePropertyValues propertyValues = beanDefinition.getPropertyValues(); if (!propertyValues.isEmpty()) { @@ -187,9 +188,8 @@ class BeanDefinitionPropertiesCodeGenerator { builder.addStatement("$L.getPropertyValues().addPropertyValue($S, $L)", BEAN_DEFINITION_VARIABLE, propertyValue.getName(), code); } - Class beanType = ClassUtils - .getUserClass(beanDefinition.getResolvableType().toClass()); - BeanInfo beanInfo = (beanType != Object.class) ? getBeanInfo(beanType) : null; + Class infrastructureType = getInfrastructureType(beanDefinition); + BeanInfo beanInfo = (infrastructureType != Object.class) ? getBeanInfo(infrastructureType) : null; if (beanInfo != null) { Map writeMethods = getWriteMethods(beanInfo); for (PropertyValue propertyValue : propertyValues) { @@ -202,6 +202,16 @@ class BeanDefinitionPropertiesCodeGenerator { } } + private Class getInfrastructureType(RootBeanDefinition beanDefinition) { + if (beanDefinition.hasBeanClass()) { + Class beanClass = beanDefinition.getBeanClass(); + if (FactoryBean.class.isAssignableFrom(beanClass)) { + return beanClass; + } + } + return ClassUtils.getUserClass(beanDefinition.getResolvableType().toClass()); + } + @Nullable private BeanInfo getBeanInfo(Class beanType) { try { diff --git a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java index d8725df503..a92cf5a6f5 100644 --- a/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java +++ b/spring-beans/src/test/java/org/springframework/beans/factory/aot/BeanDefinitionPropertiesCodeGeneratorTests.java @@ -31,6 +31,7 @@ import org.springframework.aot.generate.GeneratedClass; import org.springframework.aot.hint.predicate.RuntimeHintsPredicates; import org.springframework.aot.test.generator.compile.Compiled; import org.springframework.aot.test.generator.compile.TestCompiler; +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.ValueHolder; @@ -46,6 +47,7 @@ import org.springframework.core.testfixture.aot.generate.TestGenerationContext; import org.springframework.javapoet.CodeBlock; import org.springframework.javapoet.MethodSpec; import org.springframework.javapoet.ParameterizedTypeName; +import org.springframework.lang.Nullable; import static org.assertj.core.api.Assertions.assertThat; @@ -353,6 +355,20 @@ class BeanDefinitionPropertiesCodeGeneratorTests { }); } + @Test + void propertyValuesWhenValuesOnFactoryBeanClass() { + this.beanDefinition.setTargetType(String.class); + this.beanDefinition.setBeanClass(PropertyValuesFactoryBean.class); + this.beanDefinition.getPropertyValues().add("prefix", "Hello"); + this.beanDefinition.getPropertyValues().add("name", "World"); + compile((actual, compiled) -> { + assertThat(actual.getPropertyValues().get("prefix")).isEqualTo("Hello"); + assertThat(actual.getPropertyValues().get("name")).isEqualTo("World"); + }); + String[] methodNames = { "setPrefix", "setName" }; + assertHasMethodInvokeHints(PropertyValuesFactoryBean.class, methodNames); + } + @Test void attributesWhenAllFiltered() { this.beanDefinition.setAttribute("a", "A"); @@ -460,4 +476,40 @@ class BeanDefinitionPropertiesCodeGeneratorTests { } + static class PropertyValuesFactoryBean implements FactoryBean { + + private Class prefix; + + private String name; + + public Class getPrefix() { + return this.prefix; + } + + public void setPrefix(Class prefix) { + this.prefix = prefix; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + @Nullable + @Override + public String getObject() throws Exception { + return getPrefix() + " " + getName(); + } + + @Nullable + @Override + public Class getObjectType() { + return String.class; + } + + } + }