From a6b30a3aabfd45cce0b50cfbc0460222e4ea6770 Mon Sep 17 00:00:00 2001 From: Andy Wilkinson Date: Tue, 5 Sep 2017 10:38:08 +0100 Subject: [PATCH] =?UTF-8?q?Reflect=20context=20hierarchy=20in=20beans=20en?= =?UTF-8?q?dpoint=E2=80=99s=20response=20structure?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes gh-10156 --- .../boot/actuate/endpoint/BeansEndpoint.java | 70 +++++++++++-------- .../actuate/endpoint/BeansEndpointTests.java | 61 ++++------------ .../SampleActuatorApplicationTests.java | 6 +- 3 files changed, 58 insertions(+), 79 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java index 760dd963c27..9f52cc7df39 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/BeansEndpoint.java @@ -16,8 +16,6 @@ package org.springframework.boot.actuate.endpoint; -import java.util.ArrayList; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -32,7 +30,7 @@ import org.springframework.context.ConfigurableApplicationContext; import org.springframework.util.StringUtils; /** - * {@link Endpoint} to expose details of an application's bean, grouped by application + * {@link Endpoint} to expose details of an application's beans, grouped by application * context. * * @author Dave Syer @@ -55,50 +53,53 @@ public class BeansEndpoint { } @ReadOperation - public Map beans() { - List contexts = new ArrayList<>(); - ConfigurableApplicationContext current = this.context; - while (current != null) { - contexts.add(ApplicationContextDescriptor.describing(current)); - current = getConfigurableParent(current); - } - return Collections.singletonMap("contexts", contexts); + public ApplicationContextDescriptor beans() { + return ApplicationContextDescriptor.describing(this.context); } - private ConfigurableApplicationContext getConfigurableParent( - ConfigurableApplicationContext context) { - ApplicationContext parent = context.getParent(); - if (parent instanceof ConfigurableApplicationContext) { - return (ConfigurableApplicationContext) parent; + /** + * Response produced by the {@link BeansEndpoint}, primarily intended for + * serialization to JSON. + */ + public static class BeansEndpointResponse { + + private List contexts; + + public BeansEndpointResponse(List contexts) { + this.contexts = contexts; } - return null; + + public List getContexts() { + return this.contexts; + } + } /** * A description of an application context, primarily intended for serialization to * JSON. */ - static final class ApplicationContextDescriptor { + public static final class ApplicationContextDescriptor { private final String id; - private final String parentId; - private final Map beans; - private ApplicationContextDescriptor(String id, String parentId, - Map beans) { + private final ApplicationContextDescriptor parent; + + private ApplicationContextDescriptor(String id, Map beans, + ApplicationContextDescriptor parent) { this.id = id; - this.parentId = parentId; this.beans = beans; + this.parent = parent; } public String getId() { return this.id; } - public String getParentId() { - return this.parentId; + public ApplicationContextDescriptor getParent() { + return this.parent; } public Map getBeans() { @@ -107,10 +108,12 @@ public class BeansEndpoint { private static ApplicationContextDescriptor describing( ConfigurableApplicationContext context) { - ApplicationContext parent = context.getParent(); + if (context == null) { + return null; + } return new ApplicationContextDescriptor(context.getId(), - parent == null ? null : parent.getId(), - describeBeans(context.getBeanFactory())); + describeBeans(context.getBeanFactory()), + describing(getConfigurableParent(context))); } private static Map describeBeans( @@ -138,13 +141,22 @@ public class BeansEndpoint { && (!bd.isLazyInit() || bf.containsSingleton(beanName))); } + private static ConfigurableApplicationContext getConfigurableParent( + ConfigurableApplicationContext context) { + ApplicationContext parent = context.getParent(); + if (parent instanceof ConfigurableApplicationContext) { + return (ConfigurableApplicationContext) parent; + } + return null; + } + } /** * A description of a bean in an application context, primarily intended for * serialization to JSON. */ - static final class BeanDescriptor { + public static final class BeanDescriptor { private final String[] aliases; diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java index 7d237645644..30e3a8eadf8 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/BeansEndpointTests.java @@ -43,27 +43,22 @@ import static org.assertj.core.api.Assertions.assertThat; */ public class BeansEndpointTests { - @SuppressWarnings("unchecked") @Test public void beansAreFound() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(EndpointConfiguration.class); contextRunner.run((context) -> { - Map result = context.getBean(BeansEndpoint.class).beans(); - List contexts = (List) result - .get("contexts"); - assertThat(contexts).hasSize(1); - ApplicationContextDescriptor contextDescriptor = contexts.get(0); - assertThat(contextDescriptor.getParentId()).isNull(); - assertThat(contextDescriptor.getId()).isEqualTo(context.getId()); - Map beans = contextDescriptor.getBeans(); + ApplicationContextDescriptor result = context.getBean(BeansEndpoint.class) + .beans(); + assertThat(result.getParent()).isNull(); + assertThat(result.getId()).isEqualTo(context.getId()); + Map beans = result.getBeans(); assertThat(beans.size()) .isLessThanOrEqualTo(context.getBeanDefinitionCount()); - assertThat(contexts.get(0).getBeans()).containsKey("endpoint"); + assertThat(beans).containsKey("endpoint"); }); } - @SuppressWarnings("unchecked") @Test public void infrastructureBeansAreOmitted() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() @@ -75,32 +70,28 @@ public class BeansEndpointTests { .filter((name) -> BeanDefinition.ROLE_INFRASTRUCTURE == factory .getBeanDefinition(name).getRole()) .collect(Collectors.toList()); - Map result = context.getBean(BeansEndpoint.class).beans(); - List contexts = (List) result - .get("contexts"); - Map beans = contexts.get(0).getBeans(); + ApplicationContextDescriptor result = context.getBean(BeansEndpoint.class) + .beans(); + Map beans = result.getBeans(); for (String infrastructureBean : infrastructureBeans) { assertThat(beans).doesNotContainKey(infrastructureBean); } }); } - @SuppressWarnings("unchecked") @Test public void lazyBeansAreOmitted() { ApplicationContextRunner contextRunner = new ApplicationContextRunner() .withUserConfiguration(EndpointConfiguration.class, LazyBeanConfiguration.class); contextRunner.run((context) -> { - Map result = context.getBean(BeansEndpoint.class).beans(); - List contexts = (List) result - .get("contexts"); + ApplicationContextDescriptor result = context.getBean(BeansEndpoint.class) + .beans(); assertThat(context).hasBean("lazyBean"); - assertThat(contexts.get(0).getBeans()).doesNotContainKey("lazyBean"); + assertThat(result.getBeans()).doesNotContainKey("lazyBean"); }); } - @SuppressWarnings("unchecked") @Test public void beansInParentContextAreFound() { ApplicationContextRunner parentRunner = new ApplicationContextRunner() @@ -110,31 +101,9 @@ public class BeansEndpointTests { .withUserConfiguration(EndpointConfiguration.class).withParent(parent) .run(child -> { BeansEndpoint endpoint = child.getBean(BeansEndpoint.class); - Map result = endpoint.beans(); - List contexts = (List) result - .get("contexts"); - assertThat(contexts).hasSize(2); - assertThat(contexts.get(1).getBeans()).containsKey("bean"); - assertThat(contexts.get(0).getBeans()).containsKey("endpoint"); - }); - }); - } - - @SuppressWarnings("unchecked") - @Test - public void beansInChildContextAreNotFound() { - ApplicationContextRunner parentRunner = new ApplicationContextRunner() - .withUserConfiguration(EndpointConfiguration.class); - parentRunner.run((parent) -> { - new ApplicationContextRunner().withUserConfiguration(BeanConfiguration.class) - .withParent(parent).run(child -> { - BeansEndpoint endpoint = child.getBean(BeansEndpoint.class); - Map result = endpoint.beans(); - List contexts = (List) result - .get("contexts"); - assertThat(contexts).hasSize(1); - assertThat(contexts.get(0).getBeans()).containsKey("endpoint"); - assertThat(contexts.get(0).getBeans()).doesNotContainKey("bean"); + ApplicationContextDescriptor result = endpoint.beans(); + assertThat(result.getParent().getBeans()).containsKey("bean"); + assertThat(result.getBeans()).containsKey("endpoint"); }); }); } diff --git a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java index 322d0c266ea..72eb9340730 100644 --- a/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java +++ b/spring-boot-samples/spring-boot-sample-actuator/src/test/java/sample/actuator/SampleActuatorApplicationTests.java @@ -217,10 +217,8 @@ public class SampleActuatorApplicationTests { .withBasicAuth("user", getPassword()) .getForEntity("/application/beans", Map.class); assertThat(entity.getStatusCode()).isEqualTo(HttpStatus.OK); - assertThat(entity.getBody()).hasSize(1); - Map body = (Map) ((List) entity.getBody() - .get("contexts")).get(0); - assertThat(((String) body.get("id"))).startsWith("application"); + assertThat(entity.getBody()).containsOnlyKeys("beans", "parent", "id"); + assertThat(((String) entity.getBody().get("id"))).startsWith("application"); } @SuppressWarnings("unchecked")