From de3ce18ad6ce24ef46bb76b7cf8db9c334c8ff92 Mon Sep 17 00:00:00 2001 From: Dave Syer Date: Wed, 10 Dec 2014 10:49:01 +0000 Subject: [PATCH] Defensive check for cglib proxy in RequestMappingEndpoint Since AbstractHandlerMethodMapping.getHandlerMap() is final it can't be cglibbed and a proxy will barf if you try and call that method. The RequestMappingEndpoint can be protected simply by defensively checking if the mapping is a proxy before trying to inspect it. --- .../endpoint/RequestMappingEndpoint.java | 5 ++++ .../endpoint/RequestMappingEndpointTests.java | 29 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java index 87de684ff0..5c2a86e2e9 100644 --- a/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java +++ b/spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java @@ -23,6 +23,7 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import org.springframework.aop.support.AopUtils; import org.springframework.beans.BeansException; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.ApplicationContext; @@ -109,6 +110,10 @@ public class RequestMappingEndpoint extends AbstractEndpoint .getBeansOfType(AbstractUrlHandlerMapping.class); for (String name : mappings.keySet()) { AbstractUrlHandlerMapping mapping = mappings.get(name); + if (AopUtils.isCglibProxy(mapping)) { + // The getHandlerMap() method is final so it cannot be cglibbed + continue; + } Map handlers = mapping.getHandlerMap(); for (String key : handlers.keySet()) { result.put(key, Collections.singletonMap("bean", name)); diff --git a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java index 3e0de15719..56fcc90890 100644 --- a/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java +++ b/spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java @@ -23,6 +23,12 @@ 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.annotation.AnnotationConfigApplicationContext; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Lazy; +import org.springframework.context.annotation.Scope; +import org.springframework.context.annotation.ScopedProxyMode; import org.springframework.context.support.StaticApplicationContext; import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping; import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping; @@ -69,6 +75,18 @@ public class RequestMappingEndpointTests { assertEquals("mapping", map.get("bean")); } + @Test + public void beanUrlMappingsProxy() { + AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext( + MappingConfiguration.class); + this.endpoint.setApplicationContext(context); + Map result = this.endpoint.invoke(); + assertEquals(1, result.size()); + @SuppressWarnings("unchecked") + Map map = (Map) result.get("/foo"); + assertEquals("scopedTarget.mapping", map.get("bean")); + } + @Test public void beanMethodMappings() { StaticApplicationContext context = new StaticApplicationContext(); @@ -104,4 +122,15 @@ public class RequestMappingEndpointTests { assertTrue(handler.containsKey("method")); } + @Configuration + protected static class MappingConfiguration { + @Bean + @Lazy + @Scope(proxyMode = ScopedProxyMode.TARGET_CLASS) + public AbstractUrlHandlerMapping mapping() { + SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping(); + mapping.setUrlMap(Collections.singletonMap("/foo", new Object())); + return mapping; + } + } }