(mappingInfo.patterns.length);
@@ -599,22 +626,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
}
- private RequestMappingInfo createRequestMappingInfo(Method handlerMethod) {
- RequestMappingInfo mappingInfo = new RequestMappingInfo();
- RequestMapping mapping = AnnotationUtils.findAnnotation(handlerMethod, RequestMapping.class);
- mappingInfo.patterns = mapping.value();
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) {
- mappingInfo.methods = mapping.method();
- }
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) {
- mappingInfo.params = mapping.params();
- }
- if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) {
- mappingInfo.headers = mapping.headers();
- }
- return mappingInfo;
- }
-
/**
* Determines the combined pattern for the given methodLevelPattern and path.
* Uses the following algorithm:
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/DefaultAnnotationHandlerMapping.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
index 7e883855428..b67f84fec9c 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/DefaultAnnotationHandlerMapping.java
@@ -17,7 +17,7 @@
package org.springframework.web.servlet.mvc.annotation;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
+import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
@@ -165,8 +165,9 @@ public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandler
}
final Set urls = new LinkedHashSet();
- Class>[] handlerTypes =
- Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class>[]{handlerType};
+ Set> handlerTypes = new LinkedHashSet>();
+ handlerTypes.add(handlerType);
+ handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
for (Class> currentHandlerType : handlerTypes) {
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
@@ -187,7 +188,7 @@ public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandler
}
}
}
- }, ReflectionUtils.NON_BRIDGED_METHODS);
+ }, ReflectionUtils.USER_DECLARED_METHODS);
}
return StringUtils.toStringArray(urls);
}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
index 0087ed29ec9..f17a5c9eabe 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/ServletAnnotationControllerTests.java
@@ -174,6 +174,27 @@ public class ServletAnnotationControllerTests {
assertEquals("test", response.getContentAsString());
}
+ @Test
+ public void emptyValueMapping() throws Exception {
+ servlet = new DispatcherServlet() {
+ @Override
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(ControllerWithEmptyValueMapping.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/foo");
+ request.setContextPath("/foo");
+ request.setServletPath("");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("test", response.getContentAsString());
+ }
+
@Test
public void customAnnotationController() throws Exception {
initServlet(CustomAnnotationController.class);
@@ -382,6 +403,7 @@ public class ServletAnnotationControllerTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
+ assertEquals("page1", request.getAttribute("viewName"));
HttpSession session = request.getSession();
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
@@ -392,6 +414,7 @@ public class ServletAnnotationControllerTests {
request.setSession(session);
response = new MockHttpServletResponse();
servlet.service(request, response);
+ assertEquals("page2", request.getAttribute("viewName"));
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
@@ -419,6 +442,7 @@ public class ServletAnnotationControllerTests {
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response);
+ assertEquals("page1", request.getAttribute("viewName"));
HttpSession session = request.getSession();
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
@@ -429,12 +453,88 @@ public class ServletAnnotationControllerTests {
request.setSession(session);
response = new MockHttpServletResponse();
servlet.service(request, response);
+ assertEquals("page2", request.getAttribute("viewName"));
assertTrue(session.getAttribute("object1") != null);
assertTrue(session.getAttribute("object2") != null);
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
}
+ @Test
+ public void parameterizedAnnotatedInterface() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
+ @Override
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller", new RootBeanDefinition(MyParameterizedControllerImpl.class));
+ wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("page1", request.getAttribute("viewName"));
+ HttpSession session = request.getSession();
+ assertTrue(session.getAttribute("object1") != null);
+ assertTrue(session.getAttribute("object2") != null);
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList"));
+
+ request = new MockHttpServletRequest("POST", "/myPage");
+ request.setSession(session);
+ response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("page2", request.getAttribute("viewName"));
+ assertTrue(session.getAttribute("object1") != null);
+ assertTrue(session.getAttribute("object2") != null);
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList"));
+ }
+
+ @Test
+ public void parameterizedAnnotatedInterfaceWithOverriddenMappingsInImpl() throws Exception {
+ @SuppressWarnings("serial") DispatcherServlet servlet = new DispatcherServlet() {
+ @Override
+ protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent) {
+ GenericWebApplicationContext wac = new GenericWebApplicationContext();
+ wac.registerBeanDefinition("controller",
+ new RootBeanDefinition(MyParameterizedControllerImplWithOverriddenMappings.class));
+ wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(ModelExposingViewResolver.class));
+ wac.refresh();
+ return wac;
+ }
+ };
+ servlet.init(new MockServletConfig());
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("page1", request.getAttribute("viewName"));
+ HttpSession session = request.getSession();
+ assertTrue(session.getAttribute("object1") != null);
+ assertTrue(session.getAttribute("object2") != null);
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList"));
+
+ request = new MockHttpServletRequest("POST", "/myPage");
+ request.setSession(session);
+ response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("page2", request.getAttribute("viewName"));
+ assertTrue(session.getAttribute("object1") != null);
+ assertTrue(session.getAttribute("object2") != null);
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
+ assertTrue(((Map) session.getAttribute("model")).containsKey("testBeanList"));
+ }
+
@Test
public void adaptedHandleMethods() throws Exception {
doTestAdaptedHandleMethods(MyAdaptedController.class);
@@ -1599,6 +1699,7 @@ public class ServletAnnotationControllerTests {
assertEquals("test-{foo=bar}", response.getContentAsString());
}
+
/*
* Controllers
*/
@@ -1623,6 +1724,20 @@ public class ServletAnnotationControllerTests {
}
}
+ @Controller
+ private static class ControllerWithEmptyValueMapping {
+
+ @RequestMapping("")
+ public void myPath2(HttpServletResponse response) throws IOException {
+ response.getWriter().write("test");
+ }
+
+ @RequestMapping("/bar")
+ public void myPath3(HttpServletResponse response) throws IOException {
+ response.getWriter().write("testX");
+ }
+ }
+
@Controller
private static class MyAdaptedController {
@@ -1632,10 +1747,8 @@ public class ServletAnnotationControllerTests {
}
@RequestMapping("/myPath2.do")
- public void myHandle(@RequestParam("param1") String p1,
- @RequestParam("param2") int p2,
- @RequestHeader("header1") long h1,
- @CookieValue("cookie1") Cookie c1,
+ public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2,
+ @RequestHeader("header1") long h1, @CookieValue("cookie1") Cookie c1,
HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + p1 + "-" + p2 + "-" + h1 + "-" + c1.getValue());
}
@@ -1661,11 +1774,8 @@ public class ServletAnnotationControllerTests {
}
@RequestMapping("/myPath2.do")
- public void myHandle(@RequestParam("param1") String p1,
- int param2,
- HttpServletResponse response,
- @RequestHeader("header1") String h1,
- @CookieValue("cookie1") String c1) throws IOException {
+ public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response,
+ @RequestHeader("header1") String h1, @CookieValue("cookie1") String c1) throws IOException {
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + h1 + "-" + c1);
}
@@ -1684,11 +1794,8 @@ public class ServletAnnotationControllerTests {
private static class MyAdaptedControllerBase {
@RequestMapping("/myPath2.do")
- public void myHandle(@RequestParam("param1") T p1,
- int param2,
- @RequestHeader Integer header1,
- @CookieValue int cookie1,
- HttpServletResponse response) throws IOException {
+ public void myHandle(@RequestParam("param1") T p1, int param2, @RequestHeader Integer header1,
+ @CookieValue int cookie1, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
}
@@ -1712,11 +1819,8 @@ public class ServletAnnotationControllerTests {
}
@Override
- public void myHandle(@RequestParam("param1") String p1,
- int param2,
- @RequestHeader Integer header1,
- @CookieValue int cookie1,
- HttpServletResponse response) throws IOException {
+ public void myHandle(@RequestParam("param1") String p1, int param2, @RequestHeader Integer header1,
+ @CookieValue int cookie1, HttpServletResponse response) throws IOException {
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
}
@@ -1768,13 +1872,13 @@ public class ServletAnnotationControllerTests {
public String get(Model model) {
model.addAttribute("object1", new Object());
model.addAttribute("object2", new Object());
- return "myPage";
+ return "page1";
}
@RequestMapping(method = RequestMethod.POST)
public String post(@ModelAttribute("object1") Object object1) {
//do something with object1
- return "myPage";
+ return "page2";
}
}
@@ -1796,14 +1900,79 @@ public class ServletAnnotationControllerTests {
public String get(Model model) {
model.addAttribute("object1", new Object());
model.addAttribute("object2", new Object());
- return "myPage";
+ return "page1";
}
public String post(@ModelAttribute("object1") Object object1) {
//do something with object1
- return "myPage";
+ return "page2";
}
}
+
+ @RequestMapping("/myPage")
+ @SessionAttributes({"object1", "object2"})
+ public interface MyParameterizedControllerIfc {
+
+ @ModelAttribute("testBeanList")
+ List getTestBeans();
+
+ @RequestMapping(method = RequestMethod.GET)
+ String get(Model model);
+ }
+
+ public interface MyEditableParameterizedControllerIfc extends MyParameterizedControllerIfc {
+
+ @RequestMapping(method = RequestMethod.POST)
+ String post(@ModelAttribute("object1") T object);
+ }
+
+ @Controller
+ public static class MyParameterizedControllerImpl implements MyEditableParameterizedControllerIfc {
+
+ public List getTestBeans() {
+ List list = new LinkedList();
+ list.add(new TestBean("tb1"));
+ list.add(new TestBean("tb2"));
+ return list;
+ }
+
+ public String get(Model model) {
+ model.addAttribute("object1", new TestBean());
+ model.addAttribute("object2", new TestBean());
+ return "page1";
+ }
+
+ public String post(TestBean object) {
+ //do something with object1
+ return "page2";
+ }
+ }
+
+ @Controller
+ public static class MyParameterizedControllerImplWithOverriddenMappings implements MyEditableParameterizedControllerIfc {
+
+ @ModelAttribute("testBeanList")
+ public List getTestBeans() {
+ List list = new LinkedList();
+ list.add(new TestBean("tb1"));
+ list.add(new TestBean("tb2"));
+ return list;
+ }
+
+ @RequestMapping(method = RequestMethod.GET)
+ public String get(Model model) {
+ model.addAttribute("object1", new TestBean());
+ model.addAttribute("object2", new TestBean());
+ return "page1";
+ }
+
+ @RequestMapping(method = RequestMethod.POST)
+ public String post(@ModelAttribute("object1") TestBean object1) {
+ //do something with object1
+ return "page2";
+ }
+ }
+
@Controller
public static class MyFormController {
@@ -2191,15 +2360,15 @@ public class ServletAnnotationControllerTests {
}
}
- private static class ModelExposingViewResolver implements ViewResolver {
+ public static class ModelExposingViewResolver implements ViewResolver {
- public View resolveViewName(String viewName, Locale locale) throws Exception {
+ public View resolveViewName(final String viewName, Locale locale) throws Exception {
return new View() {
public String getContentType() {
return null;
}
-
public void render(Map model, HttpServletRequest request, HttpServletResponse response) {
+ request.setAttribute("viewName", viewName);
request.getSession().setAttribute("model", model);
}
};
diff --git a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodResolver.java b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodResolver.java
index dcb3b579faa..7ab3385893a 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodResolver.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2010 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.
@@ -17,13 +17,13 @@
package org.springframework.web.bind.annotation.support;
import java.lang.reflect.Method;
-import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Set;
+import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;
@@ -70,14 +70,17 @@ public class HandlerMethodResolver {
* Initialize a new HandlerMethodResolver for the specified handler type.
* @param handlerType the handler class to introspect
*/
- public void init(Class> handlerType) {
- Class>[] handlerTypes =
- Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class>[] {handlerType};
- for (final Class> currentHandlerType : handlerTypes) {
+ public void init(final Class> handlerType) {
+ Set> handlerTypes = new LinkedHashSet>();
+ handlerTypes.add(handlerType);
+ handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
+ for (Class> currentHandlerType : handlerTypes) {
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
public void doWith(Method method) {
- Method specificMethod = ClassUtils.getMostSpecificMethod(method, currentHandlerType);
- if (isHandlerMethod(method)) {
+ Method specificMethod = ClassUtils.getMostSpecificMethod(method, handlerType);
+ Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
+ if (isHandlerMethod(specificMethod) &&
+ (bridgedMethod == specificMethod || !isHandlerMethod(bridgedMethod))) {
handlerMethods.add(specificMethod);
}
else if (method.isAnnotationPresent(InitBinder.class)) {
@@ -87,7 +90,7 @@ public class HandlerMethodResolver {
modelAttributeMethods.add(specificMethod);
}
}
- }, ReflectionUtils.NON_BRIDGED_METHODS);
+ }, ReflectionUtils.USER_DECLARED_METHODS);
}
this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
SessionAttributes sessionAttributes = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);