diff --git a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBean.java b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBean.java index fa8cc4684f..3f111223e3 100644 --- a/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBean.java +++ b/spring-boot-project/spring-boot/src/main/java/org/springframework/boot/context/properties/ConfigurationPropertiesBean.java @@ -17,6 +17,7 @@ package org.springframework.boot.context.properties; import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Constructor; import java.lang.reflect.Method; import java.util.Iterator; @@ -156,19 +157,35 @@ public final class ConfigurationPropertiesBean { Iterator beanNames = beanFactory.getBeanNamesIterator(); while (beanNames.hasNext()) { String beanName = beanNames.next(); - try { - Object bean = beanFactory.getBean(beanName); - ConfigurationPropertiesBean propertiesBean = get(applicationContext, bean, beanName); - if (propertiesBean != null) { + if (isConfigurationPropertiesBean(beanFactory, beanName)) { + try { + Object bean = beanFactory.getBean(beanName); + ConfigurationPropertiesBean propertiesBean = get(applicationContext, bean, beanName); propertiesBeans.put(beanName, propertiesBean); } - } - catch (NoSuchBeanDefinitionException ex) { + catch (Exception ex) { + } } } return propertiesBeans; } + private static boolean isConfigurationPropertiesBean(ConfigurableListableBeanFactory beanFactory, String beanName) { + try { + if (beanFactory.getBeanDefinition(beanName).isAbstract()) { + return false; + } + if (beanFactory.findAnnotationOnBean(beanName, ConfigurationProperties.class) != null) { + return true; + } + Method factoryMethod = findFactoryMethod(beanFactory, beanName); + return findMergedAnnotation(factoryMethod, ConfigurationProperties.class).isPresent(); + } + catch (NoSuchBeanDefinitionException ex) { + return false; + } + } + /** * Return a {@link ConfigurationPropertiesBean @ConfigurationPropertiesBean} instance * for the given bean details or {@code null} if the bean is not a @@ -195,7 +212,10 @@ public final class ConfigurationPropertiesBean { } private static Method findFactoryMethod(ConfigurableApplicationContext applicationContext, String beanName) { - ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory(); + return findFactoryMethod(applicationContext.getBeanFactory(), beanName); + } + + private static Method findFactoryMethod(ConfigurableListableBeanFactory beanFactory, String beanName) { if (beanFactory.containsBeanDefinition(beanName)) { BeanDefinition beanDefinition = beanFactory.getMergedBeanDefinition(beanName); if (beanDefinition instanceof RootBeanDefinition) { @@ -260,10 +280,10 @@ public final class ConfigurationPropertiesBean { Class annotationType) { MergedAnnotation annotation = MergedAnnotation.missing(); if (factory != null) { - annotation = MergedAnnotations.from(factory, SearchStrategy.TYPE_HIERARCHY).get(annotationType); + annotation = findMergedAnnotation(factory, annotationType); } if (!annotation.isPresent()) { - annotation = MergedAnnotations.from(type, SearchStrategy.TYPE_HIERARCHY).get(annotationType); + annotation = findMergedAnnotation(type, annotationType); } if (!annotation.isPresent() && AopUtils.isAopProxy(instance)) { annotation = MergedAnnotations.from(AopUtils.getTargetClass(instance), SearchStrategy.TYPE_HIERARCHY) @@ -272,6 +292,12 @@ public final class ConfigurationPropertiesBean { return annotation.isPresent() ? annotation.synthesize() : null; } + private static MergedAnnotation findMergedAnnotation(AnnotatedElement element, + Class annotationType) { + return (element != null) ? MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY).get(annotationType) + : MergedAnnotation.missing(); + } + private static boolean isBindableConstructor(Constructor constructor) { Class declaringClass = constructor.getDeclaringClass(); Constructor bindConstructor = BindMethod.findBindConstructor(declaringClass); diff --git a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java index 56f9b7c1f6..9fffe208f0 100644 --- a/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java +++ b/spring-boot-project/spring-boot/src/test/java/org/springframework/boot/context/properties/ConfigurationPropertiesBeanTests.java @@ -29,6 +29,7 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import org.springframework.context.annotation.ImportSelector; +import org.springframework.context.annotation.Lazy; import org.springframework.core.ResolvableType; import org.springframework.core.type.AnnotationMetadata; import org.springframework.stereotype.Component; @@ -72,6 +73,16 @@ class ConfigurationPropertiesBeanTests { } } + @Test + void getAllWhenHasBadBeanDoesNotFail() { + try (AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + NonAnnotatedComponent.class, AnnotatedComponent.class, AnnotatedBeanConfiguration.class, + ValueObjectConfiguration.class, BadBeanConfiguration.class)) { + Map all = ConfigurationPropertiesBean.getAll(context); + assertThat(all).isNotEmpty(); + } + } + @Test void getWhenNotAnnotatedReturnsNull() throws Throwable { get(NonAnnotatedComponent.class, "nonAnnotatedComponent", @@ -387,6 +398,25 @@ class ConfigurationPropertiesBeanTests { } + @Configuration(proxyBeanMethods = false) + static class BadBeanConfiguration { + + @Bean + @Lazy + BadBean badBean() { + return new BadBean(); + } + + } + + static class BadBean { + + BadBean() { + throw new IllegalStateException(); + } + + } + @ConfigurationProperties @ConstructorBinding static class ValueObject {