From 7352d8e303e93b423b96d5bb92296f1da483808f Mon Sep 17 00:00:00 2001 From: Madhura Bhave Date: Tue, 11 Oct 2016 14:37:55 -0700 Subject: [PATCH] Improve EndpointHandlerMapping subclassing support Update EndpointHandlerMapping so that it can be subclasses easily. Subclasses can override the `path` that is used to map the endpoint, allowing different mapping strategies to be used. See gh-7108 --- .../endpoint/mvc/EndpointHandlerMapping.java | 42 ++++++++++++------- .../mvc/EndpointHandlerMappingTests.java | 30 +++++++++++++ 2 files changed, 57 insertions(+), 15 deletions(-) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java index 6f26034435..72ca350da9 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMapping.java @@ -27,6 +27,7 @@ import java.util.Set; import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.context.ApplicationContext; import org.springframework.util.Assert; +import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.servlet.HandlerMapping; @@ -114,33 +115,44 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping { return; } String[] patterns = getPatterns(handler, mapping); - super.registerHandlerMethod(handler, method, withNewPatterns(mapping, patterns)); + if (!ObjectUtils.isEmpty(patterns)) { + super.registerHandlerMethod(handler, method, + withNewPatterns(mapping, patterns)); + } } private String[] getPatterns(Object handler, RequestMappingInfo mapping) { - String path = getPath(handler); - String prefix = StringUtils.hasText(this.prefix) ? this.prefix + path : path; + if (handler instanceof String) { + handler = getApplicationContext().getBean((String) handler); + } + Assert.state(handler instanceof MvcEndpoint, "Only MvcEndpoints are supported"); + String path = getPath((MvcEndpoint) handler); + return (path == null ? null : getEndpointPatterns(path, mapping)); + } + + /** + * Return the path that should be used to map the given {@link MvcEndpoint}. + * @param endpoint the endpoint to map + * @return the path to use for the endpoint or {@code null} if no mapping is required + */ + protected String getPath(MvcEndpoint endpoint) { + return endpoint.getPath(); + } + + private String[] getEndpointPatterns(String path, RequestMappingInfo mapping) { + String patternPrefix = StringUtils.hasText(this.prefix) ? this.prefix + path + : path; Set defaultPatterns = mapping.getPatternsCondition().getPatterns(); if (defaultPatterns.isEmpty()) { - return new String[] { prefix, prefix + ".json" }; + return new String[] { patternPrefix, patternPrefix + ".json" }; } List patterns = new ArrayList(defaultPatterns); for (int i = 0; i < patterns.size(); i++) { - patterns.set(i, prefix + patterns.get(i)); + patterns.set(i, patternPrefix + patterns.get(i)); } return patterns.toArray(new String[patterns.size()]); } - private String getPath(Object handler) { - if (handler instanceof String) { - handler = getApplicationContext().getBean((String) handler); - } - if (handler instanceof MvcEndpoint) { - return ((MvcEndpoint) handler).getPath(); - } - return ""; - } - private RequestMappingInfo withNewPatterns(RequestMappingInfo mapping, String[] patternStrings) { PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings, diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java index 981affd1d5..8d30dc7301 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/mvc/EndpointHandlerMappingTests.java @@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.mvc; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.Collection; import org.junit.Before; import org.junit.Test; @@ -145,6 +146,19 @@ public class EndpointHandlerMappingTests { assertThat(mapping.getEndpoints(TestMvcEndpoint.class)).containsExactly(endpoint); } + @Test + public void pathNotMappedWhenGetPathReturnsNull() throws Exception { + TestMvcEndpoint endpoint = new TestMvcEndpoint(new TestEndpoint("a")); + TestActionEndpoint other = new TestActionEndpoint(new TestEndpoint("b")); + EndpointHandlerMapping mapping = new TestEndpointHandlerMapping( + Arrays.asList(endpoint, other)); + mapping.setApplicationContext(this.context); + mapping.afterPropertiesSet(); + assertThat(mapping.getHandlerMethods()).hasSize(1); + assertThat(mapping.getHandler(request("GET", "/a"))).isNull(); + assertThat(mapping.getHandler(request("POST", "/b"))).isNotNull(); + } + private MockHttpServletRequest request(String method, String requestURI) { return new MockHttpServletRequest(method, requestURI); } @@ -184,4 +198,20 @@ public class EndpointHandlerMappingTests { } + static class TestEndpointHandlerMapping extends EndpointHandlerMapping { + + TestEndpointHandlerMapping(Collection endpoints) { + super(endpoints); + } + + @Override + protected String getPath(MvcEndpoint endpoint) { + if (endpoint instanceof TestActionEndpoint) { + return super.getPath(endpoint); + } + return null; + } + + } + }