Skip to content

Commit de3ce18

Browse files
committed
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.
1 parent e772174 commit de3ce18

File tree

2 files changed

+34
-0
lines changed

2 files changed

+34
-0
lines changed

spring-boot-actuator/src/main/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpoint.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import java.util.List;
2424
import java.util.Map;
2525

26+
import org.springframework.aop.support.AopUtils;
2627
import org.springframework.beans.BeansException;
2728
import org.springframework.boot.context.properties.ConfigurationProperties;
2829
import org.springframework.context.ApplicationContext;
@@ -109,6 +110,10 @@ protected void extractHandlerMappings(ApplicationContext applicationContext,
109110
.getBeansOfType(AbstractUrlHandlerMapping.class);
110111
for (String name : mappings.keySet()) {
111112
AbstractUrlHandlerMapping mapping = mappings.get(name);
113+
if (AopUtils.isCglibProxy(mapping)) {
114+
// The getHandlerMap() method is final so it cannot be cglibbed
115+
continue;
116+
}
112117
Map<String, Object> handlers = mapping.getHandlerMap();
113118
for (String key : handlers.keySet()) {
114119
result.put(key, Collections.singletonMap("bean", name));

spring-boot-actuator/src/test/java/org/springframework/boot/actuate/endpoint/RequestMappingEndpointTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,12 @@
2323
import org.junit.Test;
2424
import org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping;
2525
import org.springframework.boot.actuate.endpoint.mvc.EndpointMvcAdapter;
26+
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
27+
import org.springframework.context.annotation.Bean;
28+
import org.springframework.context.annotation.Configuration;
29+
import org.springframework.context.annotation.Lazy;
30+
import org.springframework.context.annotation.Scope;
31+
import org.springframework.context.annotation.ScopedProxyMode;
2632
import org.springframework.context.support.StaticApplicationContext;
2733
import org.springframework.web.servlet.handler.AbstractHandlerMethodMapping;
2834
import org.springframework.web.servlet.handler.AbstractUrlHandlerMapping;
@@ -69,6 +75,18 @@ public void beanUrlMappings() {
6975
assertEquals("mapping", map.get("bean"));
7076
}
7177

78+
@Test
79+
public void beanUrlMappingsProxy() {
80+
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(
81+
MappingConfiguration.class);
82+
this.endpoint.setApplicationContext(context);
83+
Map<String, Object> result = this.endpoint.invoke();
84+
assertEquals(1, result.size());
85+
@SuppressWarnings("unchecked")
86+
Map<String, Object> map = (Map<String, Object>) result.get("/foo");
87+
assertEquals("scopedTarget.mapping", map.get("bean"));
88+
}
89+
7290
@Test
7391
public void beanMethodMappings() {
7492
StaticApplicationContext context = new StaticApplicationContext();
@@ -104,4 +122,15 @@ public void concreteMethodMappings() {
104122
assertTrue(handler.containsKey("method"));
105123
}
106124

125+
@Configuration
126+
protected static class MappingConfiguration {
127+
@Bean
128+
@Lazy
129+
@Scope(proxyMode = ScopedProxyMode.TARGET_CLASS)
130+
public AbstractUrlHandlerMapping mapping() {
131+
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
132+
mapping.setUrlMap(Collections.singletonMap("/foo", new Object()));
133+
return mapping;
134+
}
135+
}
107136
}

0 commit comments

Comments
 (0)