From c996e4335af807818205e9b3b3300598daf038d2 Mon Sep 17 00:00:00 2001 From: Stephane Nicoll Date: Sat, 4 Jun 2022 12:29:45 +0200 Subject: [PATCH] Fix singleton handling of ConfigurationProperties hints Closes gh-31248 --- ...tiesBeanFactoryInitializationAotProcessor.java | 7 ++++--- ...eanFactoryInitializationAotProcessorTests.java | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java index 268095f86f34..50ecd2e9d4fa 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessor.java @@ -39,7 +39,6 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; -import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.boot.context.properties.bind.Bindable; import org.springframework.core.ResolvableType; @@ -64,8 +63,10 @@ public BeanFactoryInitializationAotContribution processAheadOfTime(ConfigurableL String[] beanNames = beanFactory.getBeanNamesForAnnotation(ConfigurationProperties.class); List> types = new ArrayList<>(); for (String beanName : beanNames) { - BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName); - types.add(ClassUtils.getUserClass(beanDefinition.getResolvableType().toClass())); + Class beanType = beanFactory.getType(beanName, false); + if (beanType != null) { + types.add(ClassUtils.getUserClass(beanType)); + } } if (!CollectionUtils.isEmpty(types)) { return new ConfigurationPropertiesReflectionHintsContribution(types); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java index 6cafb0da70f7..918f3ced35e8 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanFactoryInitializationAotProcessorTests.java @@ -37,6 +37,7 @@ import org.springframework.beans.factory.aot.BeanFactoryInitializationAotContribution; import org.springframework.beans.factory.aot.BeanFactoryInitializationAotProcessor; import org.springframework.beans.factory.aot.BeanFactoryInitializationCode; +import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.DefaultListableBeanFactory; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.context.ApplicationContext; @@ -61,7 +62,6 @@ void configurationPropertiesBeanFactoryInitializationAotProcessorIsRegistered() assertThat(new AotFactoriesLoader(new DefaultListableBeanFactory()) .load(BeanFactoryInitializationAotProcessor.class)) .anyMatch(ConfigurationPropertiesBeanFactoryInitializationAotProcessor.class::isInstance); - } @Test @@ -71,6 +71,15 @@ void processNoMatchesReturnsNullContribution() { assertThat(this.processor.processAheadOfTime(beanFactory)).isNull(); } + @Test + void processManuallyRegisteredSingleton() { + DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); + beanFactory.registerSingleton("test", new SampleProperties()); + RuntimeHints runtimeHints = process(beanFactory); + assertThat(runtimeHints.reflection().typeHints()).singleElement() + .satisfies(javaBeanBinding(SampleProperties.class)); + } + @Test void processJavaBeanConfigurationProperties() { RuntimeHints runtimeHints = process(SampleProperties.class); @@ -245,6 +254,10 @@ private RuntimeHints process(Class... types) { for (Class type : types) { beanFactory.registerBeanDefinition(type.getName(), new RootBeanDefinition(type)); } + return process(beanFactory); + } + + private RuntimeHints process(ConfigurableListableBeanFactory beanFactory) { BeanFactoryInitializationAotContribution contribution = this.processor.processAheadOfTime(beanFactory); assertThat(contribution).isNotNull(); GenerationContext generationContext = new DefaultGenerationContext(new InMemoryGeneratedFiles());