diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java index 4528546a67..a55dc96bc9 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpoint.java @@ -17,6 +17,7 @@ package org.springframework.boot.actuate.endpoint; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -58,6 +59,7 @@ import org.springframework.util.StringUtils; * * @author Christian Dupuis * @author Dave Syer + * @author Stephane Nicoll */ @ConfigurationProperties(prefix = "endpoints.configprops") public class ConfigurationPropertiesReportEndpoint @@ -335,10 +337,13 @@ public class ConfigurationPropertiesReportEndpoint // If there's a setter, we assume it's OK to report on the value, // similarly, if there's no setter but the package names match, we assume // that its a nested class used solely for binding to config props, so it - // should be kosher. This filter is not used if there is JSON metadata for - // the property, so it's mainly for user-defined beans. - return (setter != null) || ClassUtils.getPackageName(parentType) - .equals(ClassUtils.getPackageName(type)); + // should be kosher. Lists and Maps are also auto-detected by default since + // that's what the metadata generator does. This filter is not used if there + // is JSON metadata for the property, so it's mainly for user-defined beans. + return (setter != null) + || ClassUtils.getPackageName(parentType).equals(ClassUtils.getPackageName(type)) + || Map.class.isAssignableFrom(type) + || Collection.class.isAssignableFrom(type); } private AnnotatedMethod findSetter(BeanDescription beanDesc, @@ -355,5 +360,4 @@ public class ConfigurationPropertiesReportEndpoint } } - } diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java index 66f4265c97..3dc99187c4 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/ConfigurationPropertiesReportEndpointSerializationTests.java @@ -17,6 +17,8 @@ package org.springframework.boot.actuate.endpoint; import java.net.InetAddress; +import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; @@ -33,11 +35,13 @@ import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.entry; /** * Tests for {@link ConfigurationPropertiesReportEndpoint} serialization. * * @author Dave Syer + * @author Stephane Nicoll */ public class ConfigurationPropertiesReportEndpointSerializationTests { @@ -195,6 +199,32 @@ public class ConfigurationPropertiesReportEndpointSerializationTests { assertThat(map.get("address")).isEqualTo("192.168.1.10"); } + @Test + @SuppressWarnings("unchecked") + public void testInitializedMapAndList() throws Exception { + this.context.register(InitializedMapAndListPropertiesConfig.class); + EnvironmentTestUtils.addEnvironment(this.context, "foo.map.entryOne:true", + "foo.list[0]:abc"); + this.context.refresh(); + ConfigurationPropertiesReportEndpoint report = this.context + .getBean(ConfigurationPropertiesReportEndpoint.class); + Map properties = report.invoke(); + assertThat(properties).containsKeys("foo"); + Map nestedProperties = (Map) properties + .get("foo"); + assertThat(nestedProperties).containsOnlyKeys("prefix", "properties"); + assertThat(nestedProperties.get("prefix")).isEqualTo("foo"); + Map propertiesMap = (Map) nestedProperties + .get("properties"); + assertThat(propertiesMap).containsOnlyKeys("bar", "name", "map", "list"); + Map map = (Map) propertiesMap + .get("map"); + assertThat(map).containsOnly(entry("entryOne", true)); + List list = (List) propertiesMap + .get("list"); + assertThat(list).containsExactly("abc"); + } + @Configuration @EnableConfigurationProperties public static class Base { @@ -290,6 +320,18 @@ public class ConfigurationPropertiesReportEndpointSerializationTests { } + @Configuration + @Import(Base.class) + public static class InitializedMapAndListPropertiesConfig { + + @Bean + @ConfigurationProperties(prefix = "foo") + public InitializedMapAndListProperties foo() { + return new InitializedMapAndListProperties(); + } + + } + public static class Foo { private String name = "654321"; @@ -393,4 +435,20 @@ public class ConfigurationPropertiesReportEndpointSerializationTests { } + public static class InitializedMapAndListProperties extends Foo { + + private Map map = new HashMap(); + + private List list = new ArrayList(); + + public Map getMap() { + return this.map; + } + + public List getList() { + return this.list; + } + + } + }