revised handler method resolution, in particular with respect to generic interfaces (SPR-7355)
git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@3579 50f2f4bb-b051-0410-bef5-90022cba6387
This commit is contained in:
parent
49c45c0819
commit
3f7c46e16d
|
|
@ -622,4 +622,16 @@ public abstract class ReflectionUtils {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Pre-built MethodFilter that matches all non-bridge methods
|
||||||
|
* which are not declared on <code>java.lang.Object</code>.
|
||||||
|
*/
|
||||||
|
public static MethodFilter USER_DECLARED_METHODS = new MethodFilter() {
|
||||||
|
|
||||||
|
public boolean matches(Method method) {
|
||||||
|
return (!method.isBridge() && method.getDeclaringClass() != Object.class);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -435,6 +435,9 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isHandlerMethod(Method method) {
|
protected boolean isHandlerMethod(Method method) {
|
||||||
|
if (this.mappings.containsKey(method)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
RequestMappingInfo mappingInfo = new RequestMappingInfo();
|
RequestMappingInfo mappingInfo = new RequestMappingInfo();
|
||||||
RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
RequestMapping requestMapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||||
ActionMapping actionMapping = AnnotationUtils.findAnnotation(method, ActionMapping.class);
|
ActionMapping actionMapping = AnnotationUtils.findAnnotation(method, ActionMapping.class);
|
||||||
|
|
@ -460,8 +463,11 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator
|
||||||
mappingInfo.phase = determineDefaultPhase(method);
|
mappingInfo.phase = determineDefaultPhase(method);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mappingInfo.phase != null) {
|
||||||
this.mappings.put(method, mappingInfo);
|
this.mappings.put(method, mappingInfo);
|
||||||
return (mappingInfo.phase != null);
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Method resolveHandlerMethod(PortletRequest request) throws PortletException {
|
public Method resolveHandlerMethod(PortletRequest request) throws PortletException {
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -21,6 +21,7 @@ import java.lang.reflect.Method;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.portlet.ClientDataRequest;
|
import javax.portlet.ClientDataRequest;
|
||||||
|
|
@ -145,9 +146,13 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
|
||||||
* @return <code>true</code> if at least 1 handler method has been registered;
|
* @return <code>true</code> if at least 1 handler method has been registered;
|
||||||
* <code>false</code> otherwise
|
* <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
protected boolean detectHandlerMethods(Class handlerType, final String beanName, final RequestMapping typeMapping) {
|
protected boolean detectHandlerMethods(Class<?> handlerType, final String beanName, final RequestMapping typeMapping) {
|
||||||
final Set<Boolean> handlersRegistered = new HashSet<Boolean>(1);
|
final Set<Boolean> handlersRegistered = new HashSet<Boolean>(1);
|
||||||
ReflectionUtils.doWithMethods(handlerType, new ReflectionUtils.MethodCallback() {
|
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
|
||||||
|
handlerTypes.add(handlerType);
|
||||||
|
handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
|
||||||
|
for (Class<?> currentHandlerType : handlerTypes) {
|
||||||
|
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
||||||
public void doWith(Method method) {
|
public void doWith(Method method) {
|
||||||
boolean mappingFound = false;
|
boolean mappingFound = false;
|
||||||
String[] modeKeys = new String[0];
|
String[] modeKeys = new String[0];
|
||||||
|
|
@ -209,7 +214,8 @@ public class DefaultAnnotationHandlerMapping extends AbstractMapBasedHandlerMapp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||||
|
}
|
||||||
return !handlersRegistered.isEmpty();
|
return !handlersRegistered.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
@ -496,10 +497,36 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
|
||||||
*/
|
*/
|
||||||
private class ServletHandlerMethodResolver extends HandlerMethodResolver {
|
private class ServletHandlerMethodResolver extends HandlerMethodResolver {
|
||||||
|
|
||||||
|
private final Map<Method, RequestMappingInfo> mappings = new HashMap<Method, RequestMappingInfo>();
|
||||||
|
|
||||||
private ServletHandlerMethodResolver(Class<?> handlerType) {
|
private ServletHandlerMethodResolver(Class<?> handlerType) {
|
||||||
init(handlerType);
|
init(handlerType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isHandlerMethod(Method method) {
|
||||||
|
if (this.mappings.containsKey(method)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class);
|
||||||
|
if (mapping != null) {
|
||||||
|
RequestMappingInfo mappingInfo = new RequestMappingInfo();
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
this.mappings.put(method, mappingInfo);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
|
public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException {
|
||||||
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
String lookupPath = urlPathHelper.getLookupPathForRequest(request);
|
||||||
Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);
|
Comparator<String> pathComparator = pathMatcher.getPatternComparator(lookupPath);
|
||||||
|
|
@ -507,7 +534,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
|
||||||
Set<String> allowedMethods = new LinkedHashSet<String>(7);
|
Set<String> allowedMethods = new LinkedHashSet<String>(7);
|
||||||
String resolvedMethodName = null;
|
String resolvedMethodName = null;
|
||||||
for (Method handlerMethod : getHandlerMethods()) {
|
for (Method handlerMethod : getHandlerMethods()) {
|
||||||
RequestMappingInfo mappingInfo = createRequestMappingInfo(handlerMethod);
|
RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod);
|
||||||
boolean match = false;
|
boolean match = false;
|
||||||
if (mappingInfo.hasPatterns()) {
|
if (mappingInfo.hasPatterns()) {
|
||||||
List<String> matchingPatterns = new ArrayList<String>(mappingInfo.patterns.length);
|
List<String> matchingPatterns = new ArrayList<String>(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.
|
* Determines the combined pattern for the given methodLevelPattern and path.
|
||||||
* <p>Uses the following algorithm: <ol>
|
* <p>Uses the following algorithm: <ol>
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
package org.springframework.web.servlet.mvc.annotation;
|
package org.springframework.web.servlet.mvc.annotation;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
@ -165,8 +165,9 @@ public class DefaultAnnotationHandlerMapping extends AbstractDetectingUrlHandler
|
||||||
}
|
}
|
||||||
|
|
||||||
final Set<String> urls = new LinkedHashSet<String>();
|
final Set<String> urls = new LinkedHashSet<String>();
|
||||||
Class<?>[] handlerTypes =
|
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
|
||||||
Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class<?>[]{handlerType};
|
handlerTypes.add(handlerType);
|
||||||
|
handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
|
||||||
for (Class<?> currentHandlerType : handlerTypes) {
|
for (Class<?> currentHandlerType : handlerTypes) {
|
||||||
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
||||||
public void doWith(Method method) {
|
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);
|
return StringUtils.toStringArray(urls);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -174,6 +174,27 @@ public class ServletAnnotationControllerTests {
|
||||||
assertEquals("test", response.getContentAsString());
|
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
|
@Test
|
||||||
public void customAnnotationController() throws Exception {
|
public void customAnnotationController() throws Exception {
|
||||||
initServlet(CustomAnnotationController.class);
|
initServlet(CustomAnnotationController.class);
|
||||||
|
|
@ -382,6 +403,7 @@ public class ServletAnnotationControllerTests {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
servlet.service(request, response);
|
servlet.service(request, response);
|
||||||
|
assertEquals("page1", request.getAttribute("viewName"));
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
assertTrue(session.getAttribute("object1") != null);
|
assertTrue(session.getAttribute("object1") != null);
|
||||||
assertTrue(session.getAttribute("object2") != null);
|
assertTrue(session.getAttribute("object2") != null);
|
||||||
|
|
@ -392,6 +414,7 @@ public class ServletAnnotationControllerTests {
|
||||||
request.setSession(session);
|
request.setSession(session);
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
servlet.service(request, response);
|
servlet.service(request, response);
|
||||||
|
assertEquals("page2", request.getAttribute("viewName"));
|
||||||
assertTrue(session.getAttribute("object1") != null);
|
assertTrue(session.getAttribute("object1") != null);
|
||||||
assertTrue(session.getAttribute("object2") != null);
|
assertTrue(session.getAttribute("object2") != null);
|
||||||
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
|
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
|
||||||
|
|
@ -419,6 +442,7 @@ public class ServletAnnotationControllerTests {
|
||||||
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
|
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPage");
|
||||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||||
servlet.service(request, response);
|
servlet.service(request, response);
|
||||||
|
assertEquals("page1", request.getAttribute("viewName"));
|
||||||
HttpSession session = request.getSession();
|
HttpSession session = request.getSession();
|
||||||
assertTrue(session.getAttribute("object1") != null);
|
assertTrue(session.getAttribute("object1") != null);
|
||||||
assertTrue(session.getAttribute("object2") != null);
|
assertTrue(session.getAttribute("object2") != null);
|
||||||
|
|
@ -429,12 +453,88 @@ public class ServletAnnotationControllerTests {
|
||||||
request.setSession(session);
|
request.setSession(session);
|
||||||
response = new MockHttpServletResponse();
|
response = new MockHttpServletResponse();
|
||||||
servlet.service(request, response);
|
servlet.service(request, response);
|
||||||
|
assertEquals("page2", request.getAttribute("viewName"));
|
||||||
assertTrue(session.getAttribute("object1") != null);
|
assertTrue(session.getAttribute("object1") != null);
|
||||||
assertTrue(session.getAttribute("object2") != null);
|
assertTrue(session.getAttribute("object2") != null);
|
||||||
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
|
assertTrue(((Map) session.getAttribute("model")).containsKey("object1"));
|
||||||
assertTrue(((Map) session.getAttribute("model")).containsKey("object2"));
|
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
|
@Test
|
||||||
public void adaptedHandleMethods() throws Exception {
|
public void adaptedHandleMethods() throws Exception {
|
||||||
doTestAdaptedHandleMethods(MyAdaptedController.class);
|
doTestAdaptedHandleMethods(MyAdaptedController.class);
|
||||||
|
|
@ -1599,6 +1699,7 @@ public class ServletAnnotationControllerTests {
|
||||||
assertEquals("test-{foo=bar}", response.getContentAsString());
|
assertEquals("test-{foo=bar}", response.getContentAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Controllers
|
* 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
|
@Controller
|
||||||
private static class MyAdaptedController {
|
private static class MyAdaptedController {
|
||||||
|
|
||||||
|
|
@ -1632,10 +1747,8 @@ public class ServletAnnotationControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/myPath2.do")
|
@RequestMapping("/myPath2.do")
|
||||||
public void myHandle(@RequestParam("param1") String p1,
|
public void myHandle(@RequestParam("param1") String p1, @RequestParam("param2") int p2,
|
||||||
@RequestParam("param2") int p2,
|
@RequestHeader("header1") long h1, @CookieValue("cookie1") Cookie c1,
|
||||||
@RequestHeader("header1") long h1,
|
|
||||||
@CookieValue("cookie1") Cookie c1,
|
|
||||||
HttpServletResponse response) throws IOException {
|
HttpServletResponse response) throws IOException {
|
||||||
response.getWriter().write("test-" + p1 + "-" + p2 + "-" + h1 + "-" + c1.getValue());
|
response.getWriter().write("test-" + p1 + "-" + p2 + "-" + h1 + "-" + c1.getValue());
|
||||||
}
|
}
|
||||||
|
|
@ -1661,11 +1774,8 @@ public class ServletAnnotationControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping("/myPath2.do")
|
@RequestMapping("/myPath2.do")
|
||||||
public void myHandle(@RequestParam("param1") String p1,
|
public void myHandle(@RequestParam("param1") String p1, int param2, HttpServletResponse response,
|
||||||
int param2,
|
@RequestHeader("header1") String h1, @CookieValue("cookie1") String c1) throws IOException {
|
||||||
HttpServletResponse response,
|
|
||||||
@RequestHeader("header1") String h1,
|
|
||||||
@CookieValue("cookie1") String c1) throws IOException {
|
|
||||||
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + h1 + "-" + c1);
|
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + h1 + "-" + c1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1684,11 +1794,8 @@ public class ServletAnnotationControllerTests {
|
||||||
private static class MyAdaptedControllerBase<T> {
|
private static class MyAdaptedControllerBase<T> {
|
||||||
|
|
||||||
@RequestMapping("/myPath2.do")
|
@RequestMapping("/myPath2.do")
|
||||||
public void myHandle(@RequestParam("param1") T p1,
|
public void myHandle(@RequestParam("param1") T p1, int param2, @RequestHeader Integer header1,
|
||||||
int param2,
|
@CookieValue int cookie1, HttpServletResponse response) throws IOException {
|
||||||
@RequestHeader Integer header1,
|
|
||||||
@CookieValue int cookie1,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
|
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1712,11 +1819,8 @@ public class ServletAnnotationControllerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void myHandle(@RequestParam("param1") String p1,
|
public void myHandle(@RequestParam("param1") String p1, int param2, @RequestHeader Integer header1,
|
||||||
int param2,
|
@CookieValue int cookie1, HttpServletResponse response) throws IOException {
|
||||||
@RequestHeader Integer header1,
|
|
||||||
@CookieValue int cookie1,
|
|
||||||
HttpServletResponse response) throws IOException {
|
|
||||||
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
|
response.getWriter().write("test-" + p1 + "-" + param2 + "-" + header1 + "-" + cookie1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1768,13 +1872,13 @@ public class ServletAnnotationControllerTests {
|
||||||
public String get(Model model) {
|
public String get(Model model) {
|
||||||
model.addAttribute("object1", new Object());
|
model.addAttribute("object1", new Object());
|
||||||
model.addAttribute("object2", new Object());
|
model.addAttribute("object2", new Object());
|
||||||
return "myPage";
|
return "page1";
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(method = RequestMethod.POST)
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
public String post(@ModelAttribute("object1") Object object1) {
|
public String post(@ModelAttribute("object1") Object object1) {
|
||||||
//do something with object1
|
//do something with object1
|
||||||
return "myPage";
|
return "page2";
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1796,14 +1900,79 @@ public class ServletAnnotationControllerTests {
|
||||||
public String get(Model model) {
|
public String get(Model model) {
|
||||||
model.addAttribute("object1", new Object());
|
model.addAttribute("object1", new Object());
|
||||||
model.addAttribute("object2", new Object());
|
model.addAttribute("object2", new Object());
|
||||||
return "myPage";
|
return "page1";
|
||||||
}
|
}
|
||||||
|
|
||||||
public String post(@ModelAttribute("object1") Object object1) {
|
public String post(@ModelAttribute("object1") Object object1) {
|
||||||
//do something with object1
|
//do something with object1
|
||||||
return "myPage";
|
return "page2";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@RequestMapping("/myPage")
|
||||||
|
@SessionAttributes({"object1", "object2"})
|
||||||
|
public interface MyParameterizedControllerIfc<T> {
|
||||||
|
|
||||||
|
@ModelAttribute("testBeanList")
|
||||||
|
List<TestBean> getTestBeans();
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.GET)
|
||||||
|
String get(Model model);
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface MyEditableParameterizedControllerIfc<T> extends MyParameterizedControllerIfc<T> {
|
||||||
|
|
||||||
|
@RequestMapping(method = RequestMethod.POST)
|
||||||
|
String post(@ModelAttribute("object1") T object);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Controller
|
||||||
|
public static class MyParameterizedControllerImpl implements MyEditableParameterizedControllerIfc<TestBean> {
|
||||||
|
|
||||||
|
public List<TestBean> getTestBeans() {
|
||||||
|
List<TestBean> list = new LinkedList<TestBean>();
|
||||||
|
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<TestBean> {
|
||||||
|
|
||||||
|
@ModelAttribute("testBeanList")
|
||||||
|
public List<TestBean> getTestBeans() {
|
||||||
|
List<TestBean> list = new LinkedList<TestBean>();
|
||||||
|
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
|
@Controller
|
||||||
public static class MyFormController {
|
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() {
|
return new View() {
|
||||||
public String getContentType() {
|
public String getContentType() {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
|
public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response) {
|
||||||
|
request.setAttribute("viewName", viewName);
|
||||||
request.getSession().setAttribute("model", model);
|
request.getSession().setAttribute("model", model);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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;
|
package org.springframework.web.bind.annotation.support;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Proxy;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashSet;
|
import java.util.LinkedHashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.springframework.core.BridgeMethodResolver;
|
||||||
import org.springframework.core.annotation.AnnotationUtils;
|
import org.springframework.core.annotation.AnnotationUtils;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
@ -70,14 +70,17 @@ public class HandlerMethodResolver {
|
||||||
* Initialize a new HandlerMethodResolver for the specified handler type.
|
* Initialize a new HandlerMethodResolver for the specified handler type.
|
||||||
* @param handlerType the handler class to introspect
|
* @param handlerType the handler class to introspect
|
||||||
*/
|
*/
|
||||||
public void init(Class<?> handlerType) {
|
public void init(final Class<?> handlerType) {
|
||||||
Class<?>[] handlerTypes =
|
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
|
||||||
Proxy.isProxyClass(handlerType) ? handlerType.getInterfaces() : new Class<?>[] {handlerType};
|
handlerTypes.add(handlerType);
|
||||||
for (final Class<?> currentHandlerType : handlerTypes) {
|
handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
|
||||||
|
for (Class<?> currentHandlerType : handlerTypes) {
|
||||||
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
||||||
public void doWith(Method method) {
|
public void doWith(Method method) {
|
||||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, currentHandlerType);
|
Method specificMethod = ClassUtils.getMostSpecificMethod(method, handlerType);
|
||||||
if (isHandlerMethod(method)) {
|
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||||
|
if (isHandlerMethod(specificMethod) &&
|
||||||
|
(bridgedMethod == specificMethod || !isHandlerMethod(bridgedMethod))) {
|
||||||
handlerMethods.add(specificMethod);
|
handlerMethods.add(specificMethod);
|
||||||
}
|
}
|
||||||
else if (method.isAnnotationPresent(InitBinder.class)) {
|
else if (method.isAnnotationPresent(InitBinder.class)) {
|
||||||
|
|
@ -87,7 +90,7 @@ public class HandlerMethodResolver {
|
||||||
modelAttributeMethods.add(specificMethod);
|
modelAttributeMethods.add(specificMethod);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}, ReflectionUtils.NON_BRIDGED_METHODS);
|
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||||
}
|
}
|
||||||
this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
||||||
SessionAttributes sessionAttributes = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
|
SessionAttributes sessionAttributes = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue