Add /mappings endpoint
Lists AbstractUrlMappings and AbstractHandlerMethodMappings
in a loose Map structure. E.g.
{
"/**/favicon.ico": {
"bean": "faviconHandlerMapping"
},
"/**": {
"bean": "resourceHandlerMapping"
},
"/webjars/**": {
"bean": "resourceHandlerMapping"
},
"{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}":
{
"bean": "requestMappingHandlerMapping",
"method": "public java.util.Map<java.lang.String, java.lang.Object> org.springframework.boot.actuate.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)"
...
}
Fixes gh-378
This commit is contained in:
@@ -34,6 +34,7 @@ import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.PublicMetrics;
|
||||
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.VanillaPublicMetrics;
|
||||
@@ -47,6 +48,7 @@ import org.springframework.boot.actuate.trace.TraceRepository;
|
||||
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.boot.autoconfigure.condition.SearchStrategy;
|
||||
import org.springframework.boot.bind.PropertiesConfigurationFactory;
|
||||
@@ -56,6 +58,7 @@ import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.StandardEnvironment;
|
||||
import org.springframework.core.io.Resource;
|
||||
import org.springframework.core.io.support.PropertiesLoaderUtils;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
|
||||
/**
|
||||
* {@link EnableAutoConfiguration Auto-configuration} for common management
|
||||
@@ -160,6 +163,19 @@ public class EndpointAutoConfiguration {
|
||||
return new ShutdownEndpoint();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnClass(AbstractHandlerMethodMapping.class)
|
||||
protected static class RequestMappingEndpointConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public RequestMappingEndpoint requestMappingEndpoint() {
|
||||
RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public ConfigurationPropertiesReportEndpoint configurationPropertiesReportEndpoint() {
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class RequestMappingEndpoint extends AbstractEndpoint<Map<String, Object>>
|
||||
implements ApplicationContextAware {
|
||||
|
||||
private List<AbstractUrlHandlerMapping> handlerMappings = Collections.emptyList();
|
||||
|
||||
private List<AbstractHandlerMethodMapping<?>> methodMappings = Collections
|
||||
.emptyList();
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
public RequestMappingEndpoint() {
|
||||
super("mappings");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param handlerMappings the mappings to set
|
||||
*/
|
||||
public void setHandlerMappings(List<AbstractUrlHandlerMapping> handlerMappings) {
|
||||
this.handlerMappings = handlerMappings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param methodMappings the method mappings to set
|
||||
*/
|
||||
public void setMethodMappings(List<AbstractHandlerMethodMapping<?>> methodMappings) {
|
||||
this.methodMappings = methodMappings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> invoke() {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
extractHandlerMappings(this.handlerMappings, result);
|
||||
extractHandlerMappings(this.applicationContext, result);
|
||||
extractMethodMappings(this.methodMappings, result);
|
||||
extractMethodMappings(this.applicationContext, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
protected void extractMethodMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
Map<String, AbstractHandlerMethodMapping<?>> mappings = new HashMap<String, AbstractHandlerMethodMapping<?>>();
|
||||
for (String name : applicationContext.getBeansOfType(
|
||||
AbstractHandlerMethodMapping.class).keySet()) {
|
||||
mappings.put(name, applicationContext.getBean(name,
|
||||
AbstractHandlerMethodMapping.class));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<?, HandlerMethod> methods = applicationContext.getBean(name,
|
||||
AbstractHandlerMethodMapping.class).getHandlerMethods();
|
||||
for (Object key : methods.keySet()) {
|
||||
Map<String, String> map = new LinkedHashMap<String, String>();
|
||||
map.put("bean", name);
|
||||
map.put("method", methods.get(key).toString());
|
||||
result.put(key.toString(), map);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(ApplicationContext applicationContext,
|
||||
Map<String, Object> result) {
|
||||
if (applicationContext != null) {
|
||||
Map<String, AbstractUrlHandlerMapping> mappings = applicationContext
|
||||
.getBeansOfType(AbstractUrlHandlerMapping.class);
|
||||
for (String name : mappings.keySet()) {
|
||||
AbstractUrlHandlerMapping mapping = mappings.get(name);
|
||||
Map<String, Object> handlers = mapping.getHandlerMap();
|
||||
for (String key : handlers.keySet()) {
|
||||
result.put(key, Collections.singletonMap("bean", name));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractHandlerMappings(
|
||||
Collection<AbstractUrlHandlerMapping> handlerMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractUrlHandlerMapping mapping : handlerMappings) {
|
||||
Map<String, Object> handlers = mapping.getHandlerMap();
|
||||
for (String key : handlers.keySet()) {
|
||||
Object handler = handlers.get(key);
|
||||
result.put(key,
|
||||
Collections.singletonMap("type", handler.getClass().getName()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void extractMethodMappings(
|
||||
Collection<AbstractHandlerMethodMapping<?>> methodMappings,
|
||||
Map<String, Object> result) {
|
||||
for (AbstractHandlerMethodMapping<?> mapping : methodMappings) {
|
||||
Map<?, HandlerMethod> methods = mapping.getHandlerMethods();
|
||||
for (Object key : methods.keySet()) {
|
||||
result.put(key.toString(),
|
||||
Collections.singletonMap("method", methods.get(key).toString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@ import org.springframework.boot.actuate.endpoint.EnvironmentEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.HealthEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.InfoEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.MetricsEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.RequestMappingEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.ShutdownEndpoint;
|
||||
import org.springframework.boot.actuate.endpoint.TraceEndpoint;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionEvaluationReport;
|
||||
@@ -75,6 +76,7 @@ public class EndpointAutoConfigurationTests {
|
||||
assertNotNull(this.context.getBean(MetricsEndpoint.class));
|
||||
assertNotNull(this.context.getBean(ShutdownEndpoint.class));
|
||||
assertNotNull(this.context.getBean(TraceEndpoint.class));
|
||||
assertNotNull(this.context.getBean(RequestMappingEndpoint.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright 2012-2013 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.actuate.endpoint;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
|
||||
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
|
||||
import org.springframework.context.support.StaticApplicationContext;
|
||||
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
|
||||
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
|
||||
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class RequestMappingEndpointTests {
|
||||
|
||||
private RequestMappingEndpoint endpoint = new RequestMappingEndpoint();
|
||||
|
||||
@Test
|
||||
public void concreteUrlMappings() {
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
|
||||
mapping.setApplicationContext(new StaticApplicationContext());
|
||||
mapping.initApplicationContext();
|
||||
this.endpoint.setHandlerMappings(Collections
|
||||
.<AbstractUrlHandlerMapping> singletonList(mapping));
|
||||
Map<String, Object> result = this.endpoint.invoke();
|
||||
assertEquals(1, result.size());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
|
||||
assertEquals("java.lang.Object", map.get("type"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanUrlMappings() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
|
||||
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
|
||||
mapping.setApplicationContext(context);
|
||||
mapping.initApplicationContext();
|
||||
context.getDefaultListableBeanFactory().registerSingleton("mapping", mapping);
|
||||
this.endpoint.setApplicationContext(context);
|
||||
Map<String, Object> result = this.endpoint.invoke();
|
||||
assertEquals(1, result.size());
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
|
||||
assertEquals("mapping", map.get("bean"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanMethodMappings() {
|
||||
StaticApplicationContext context = new StaticApplicationContext();
|
||||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
|
||||
Arrays.asList(new EndpointMvcAdapter(new DumpEndpoint())));
|
||||
mapping.setApplicationContext(new StaticApplicationContext());
|
||||
mapping.afterPropertiesSet();
|
||||
context.getDefaultListableBeanFactory().registerSingleton("mapping", mapping);
|
||||
this.endpoint.setApplicationContext(context);
|
||||
Map<String, Object> result = this.endpoint.invoke();
|
||||
assertEquals(1, result.size());
|
||||
assertTrue(result.keySet().iterator().next().contains("/dump"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> handler = (Map<String, Object>) result.values().iterator()
|
||||
.next();
|
||||
assertTrue(handler.containsKey("method"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void concreteMethodMappings() {
|
||||
EndpointHandlerMapping mapping = new EndpointHandlerMapping(
|
||||
Arrays.asList(new EndpointMvcAdapter(new DumpEndpoint())));
|
||||
mapping.setApplicationContext(new StaticApplicationContext());
|
||||
mapping.afterPropertiesSet();
|
||||
this.endpoint.setMethodMappings(Collections
|
||||
.<AbstractHandlerMethodMapping<?>> singletonList(mapping));
|
||||
Map<String, Object> result = this.endpoint.invoke();
|
||||
assertEquals(1, result.size());
|
||||
assertTrue(result.keySet().iterator().next().contains("/dump"));
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> handler = (Map<String, Object>) result.values().iterator()
|
||||
.next();
|
||||
assertTrue(handler.containsKey("method"));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user