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
pull/7164/head
Madhura Bhave 8 years ago committed by Phillip Webb
parent 0be8a30276
commit 7352d8e303

@ -27,6 +27,7 @@ import java.util.Set;
import org.springframework.boot.actuate.endpoint.Endpoint; import org.springframework.boot.actuate.endpoint.Endpoint;
import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.servlet.HandlerMapping; import org.springframework.web.servlet.HandlerMapping;
@ -114,33 +115,44 @@ public class EndpointHandlerMapping extends RequestMappingHandlerMapping {
return; return;
} }
String[] patterns = getPatterns(handler, mapping); 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) { private String[] getPatterns(Object handler, RequestMappingInfo mapping) {
String path = getPath(handler); if (handler instanceof String) {
String prefix = StringUtils.hasText(this.prefix) ? this.prefix + path : path; 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<String> defaultPatterns = mapping.getPatternsCondition().getPatterns(); Set<String> defaultPatterns = mapping.getPatternsCondition().getPatterns();
if (defaultPatterns.isEmpty()) { if (defaultPatterns.isEmpty()) {
return new String[] { prefix, prefix + ".json" }; return new String[] { patternPrefix, patternPrefix + ".json" };
} }
List<String> patterns = new ArrayList<String>(defaultPatterns); List<String> patterns = new ArrayList<String>(defaultPatterns);
for (int i = 0; i < patterns.size(); i++) { 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()]); 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, private RequestMappingInfo withNewPatterns(RequestMappingInfo mapping,
String[] patternStrings) { String[] patternStrings) {
PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings, PatternsRequestCondition patterns = new PatternsRequestCondition(patternStrings,

@ -18,6 +18,7 @@ package org.springframework.boot.actuate.endpoint.mvc;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
@ -145,6 +146,19 @@ public class EndpointHandlerMappingTests {
assertThat(mapping.getEndpoints(TestMvcEndpoint.class)).containsExactly(endpoint); 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) { private MockHttpServletRequest request(String method, String requestURI) {
return new MockHttpServletRequest(method, requestURI); return new MockHttpServletRequest(method, requestURI);
} }
@ -184,4 +198,20 @@ public class EndpointHandlerMappingTests {
} }
static class TestEndpointHandlerMapping extends EndpointHandlerMapping {
TestEndpointHandlerMapping(Collection<? extends MvcEndpoint> endpoints) {
super(endpoints);
}
@Override
protected String getPath(MvcEndpoint endpoint) {
if (endpoint instanceof TestActionEndpoint) {
return super.getPath(endpoint);
}
return null;
}
}
} }

Loading…
Cancel
Save