Skip to content

Commit 17d5b31

Browse files
committed
SPR-6206 - When looking up methods with @RequestMapping annotation, unannotated bridge methods are included
1 parent 52ad49b commit 17d5b31

File tree

3 files changed

+162
-2
lines changed

3 files changed

+162
-2
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/*
2+
* Copyright 2002-2009 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.web.servlet.mvc.annotation;
18+
19+
import java.io.IOException;
20+
import java.io.Writer;
21+
import javax.servlet.ServletException;
22+
23+
import static org.junit.Assert.*;
24+
import org.junit.Test;
25+
26+
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
27+
import org.springframework.aop.interceptor.SimpleTraceInterceptor;
28+
import org.springframework.aop.support.DefaultPointcutAdvisor;
29+
import org.springframework.beans.BeansException;
30+
import org.springframework.beans.factory.support.RootBeanDefinition;
31+
import org.springframework.mock.web.MockHttpServletRequest;
32+
import org.springframework.mock.web.MockHttpServletResponse;
33+
import org.springframework.mock.web.MockServletConfig;
34+
import org.springframework.stereotype.Controller;
35+
import org.springframework.web.bind.annotation.RequestMapping;
36+
import org.springframework.web.context.WebApplicationContext;
37+
import org.springframework.web.context.support.GenericWebApplicationContext;
38+
import org.springframework.web.servlet.DispatcherServlet;
39+
40+
/**
41+
* @author Arjen Poutsma
42+
* @since 3.0
43+
*/
44+
public class CgLibProxyServletAnnotationTests {
45+
46+
private DispatcherServlet servlet;
47+
48+
@Test
49+
public void typeLevel() throws Exception {
50+
initServlet(TypeLevelImpl.class);
51+
52+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
53+
MockHttpServletResponse response = new MockHttpServletResponse();
54+
servlet.service(request, response);
55+
assertEquals("doIt", response.getContentAsString());
56+
}
57+
58+
@Test
59+
public void methodLevel() throws Exception {
60+
initServlet(MethodLevelImpl.class);
61+
62+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test");
63+
MockHttpServletResponse response = new MockHttpServletResponse();
64+
servlet.service(request, response);
65+
assertEquals("doIt", response.getContentAsString());
66+
}
67+
68+
@Test
69+
public void typeAndMethodLevel() throws Exception {
70+
initServlet(TypeAndMethodLevelImpl.class);
71+
72+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/bookings");
73+
MockHttpServletResponse response = new MockHttpServletResponse();
74+
servlet.service(request, response);
75+
assertEquals("doIt", response.getContentAsString());
76+
}
77+
78+
79+
private void initServlet(final Class<?> controllerclass) throws ServletException {
80+
servlet = new DispatcherServlet() {
81+
@Override
82+
protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)
83+
throws BeansException {
84+
GenericWebApplicationContext wac = new GenericWebApplicationContext();
85+
wac.registerBeanDefinition("controller", new RootBeanDefinition(controllerclass));
86+
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
87+
autoProxyCreator.setProxyTargetClass(true);
88+
autoProxyCreator.setBeanFactory(wac.getBeanFactory());
89+
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
90+
wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor(true)));
91+
wac.refresh();
92+
return wac;
93+
}
94+
};
95+
servlet.init(new MockServletConfig());
96+
}
97+
98+
/*
99+
* Controllers
100+
*/
101+
102+
@Controller
103+
@RequestMapping("/test")
104+
public static class TypeLevelImpl {
105+
106+
@RequestMapping
107+
public void doIt(Writer writer) throws IOException {
108+
writer.write("doIt");
109+
}
110+
}
111+
112+
@Controller
113+
public static class MethodLevelImpl {
114+
115+
@RequestMapping("/test")
116+
public void doIt(Writer writer) throws IOException {
117+
writer.write("doIt");
118+
}
119+
}
120+
121+
@Controller
122+
@RequestMapping("/hotels")
123+
public static class TypeAndMethodLevelImpl {
124+
125+
@RequestMapping("/bookings")
126+
public void doIt(Writer writer) throws IOException {
127+
writer.write("doIt");
128+
}
129+
}
130+
131+
}

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,16 @@ public void ambiguousParams() throws ServletException, IOException {
11211121
assertEquals("myParam-42", response.getContentAsString());
11221122
}
11231123

1124+
@Test
1125+
public void bridgeMethods() throws Exception {
1126+
initServlet(TestControllerImpl.class);
1127+
1128+
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/method");
1129+
MockHttpServletResponse response = new MockHttpServletResponse();
1130+
servlet.service(request, response);
1131+
}
1132+
1133+
11241134

11251135
/*
11261136
* Controllers
@@ -1900,4 +1910,23 @@ public void handle(@CookieValue("date") Date date, Writer writer)
19001910
}
19011911
}
19021912

1913+
public interface TestController<T> {
1914+
1915+
ModelAndView method(T object);
1916+
}
1917+
1918+
public static class MyEntity {
1919+
1920+
}
1921+
1922+
@Controller
1923+
public static class TestControllerImpl implements TestController<MyEntity> {
1924+
1925+
@RequestMapping("/method")
1926+
public ModelAndView method(MyEntity object) {
1927+
return new ModelAndView("/something");
1928+
}
1929+
}
1930+
1931+
19031932
}

org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodResolver.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public void init(Class<?> handlerType) {
7777
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
7878
public void doWith(Method method) {
7979
Method specificMethod = ClassUtils.getMostSpecificMethod(method, currentHandlerType);
80-
if (isHandlerMethod(specificMethod)) {
80+
if (isHandlerMethod(method)) {
8181
handlerMethods.add(specificMethod);
8282
}
8383
else if (method.isAnnotationPresent(InitBinder.class)) {
@@ -99,7 +99,7 @@ else if (method.isAnnotationPresent(ModelAttribute.class)) {
9999
}
100100

101101
protected boolean isHandlerMethod(Method method) {
102-
return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
102+
return method.isAnnotationPresent(RequestMapping.class);
103103
}
104104

105105

0 commit comments

Comments
 (0)