From e6c75e7de90356de93ddac254863f91ae4c5d333 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Wed, 19 Nov 2008 17:08:34 +0000 Subject: [PATCH] SPR-5251: URI Templates support relative @RequestMappings (on class level, with more specific mapping on method level) git-svn-id: https://src.springframework.org/svn/spring-framework/trunk@302 50f2f4bb-b051-0410-bef5-90022cba6387 --- .../AnnotationMethodHandlerAdapter.java | 34 +++++++++++++++ ...plateServletAnnotationControllerTests.java | 43 +++++++++++++++++-- 2 files changed, 73 insertions(+), 4 deletions(-) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index d7dcd327471..b805b0fb8e0 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -51,6 +51,7 @@ import org.springframework.ui.Model; import org.springframework.util.AntPathMatcher; import org.springframework.util.Assert; import org.springframework.util.ClassUtils; +import org.springframework.util.CollectionUtils; import org.springframework.util.PathMatcher; import org.springframework.util.StringUtils; import org.springframework.validation.support.BindingAwareModelMap; @@ -503,6 +504,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen } } if (targetHandlerMethods.size() == 1) { + extractHandlerMethodUriTemplates(targetPathMatches.values().iterator().next(), lookupPath, request); return targetHandlerMethods.values().iterator().next(); } else if (!targetHandlerMethods.isEmpty()) { @@ -525,6 +527,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen } } } + extractHandlerMethodUriTemplates(bestPathMatch, lookupPath, request); return targetHandlerMethods.get(bestMappingMatch); } else { @@ -570,6 +573,37 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen private boolean isBetterParamMatch(RequestMappingInfo mapping, RequestMappingInfo mappingToCompare) { return (mappingToCompare.params.length < mapping.params.length); } + + @SuppressWarnings("unchecked") + private void extractHandlerMethodUriTemplates(String mappedPath, String lookupPath, HttpServletRequest request) { + Map variables = null; + boolean hasSuffix = (mappedPath.indexOf('.') != -1); + if (!hasSuffix && pathMatcher.match(mappedPath + ".*", lookupPath)) { + String realPath = mappedPath + ".*"; + if (pathMatcher.match(realPath, lookupPath)) { + variables = pathMatcher.extractUriTemplateVariables(realPath, lookupPath); + } + } + if (variables == null && !mappedPath.startsWith("/")) { + String realPath = "/**/" + mappedPath; + if (pathMatcher.match(realPath, lookupPath)) { + variables = pathMatcher.extractUriTemplateVariables(realPath, lookupPath); + } else { + realPath = realPath + ".*"; + if (pathMatcher.match(realPath, lookupPath)) { + variables = pathMatcher.extractUriTemplateVariables(realPath, lookupPath); + } + } + } + if (!CollectionUtils.isEmpty(variables)) { + Map typeVariables = + (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); + if (typeVariables != null) { + variables.putAll(typeVariables); + } + request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, variables); + } + } } diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/UriTemplateServletAnnotationControllerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/UriTemplateServletAnnotationControllerTests.java index dcbad780a13..9ee967890fc 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/UriTemplateServletAnnotationControllerTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/UriTemplateServletAnnotationControllerTests.java @@ -5,7 +5,6 @@ import java.io.Writer; import java.text.SimpleDateFormat; import java.util.Date; import javax.servlet.ServletException; -import javax.servlet.http.HttpServletResponse; import static org.junit.Assert.assertEquals; import org.junit.Test; @@ -50,6 +49,26 @@ public class UriTemplateServletAnnotationControllerTests { assertEquals("test-42", response.getContentAsString()); } + @Test + public void ambiguous() throws Exception { + initServlet(AmbiguousUriTemplateController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/12345"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("specific", response.getContentAsString()); + } + + @Test + public void relative() throws Exception { + initServlet(RelativePathUriTemplateController.class); + + MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels/42/bookings/21"); + MockHttpServletResponse response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("test-42-21", response.getContentAsString()); + } + private void initServlet(final Class controllerclass) throws ServletException { servlet = new DispatcherServlet() { @Override @@ -101,10 +120,26 @@ public class UriTemplateServletAnnotationControllerTests { @RequestMapping("/hotels/{hotel}/**") public static class RelativePathUriTemplateController { - @RequestMapping("/bookings/{booking}") - public void handle(@PathVariable("hotel") int hotel, @PathVariable int booking, HttpServletResponse response) + @RequestMapping("bookings/{booking}") + public void handle(@PathVariable("hotel") String hotel, @PathVariable int booking, Writer writer) throws IOException { - response.getWriter().write("test-" + hotel + "-" + booking); + assertEquals("Invalid path variable value", "42", hotel); + assertEquals("Invalid path variable value", 21, booking); + writer.write("test-" + hotel + "-" + booking); + } + + } + + @Controller + public static class AmbiguousUriTemplateController { + @RequestMapping("/hotels/{hotel}") + public void handleVars(Writer writer) throws IOException { + writer.write("variables"); + } + + @RequestMapping("/hotels/12345") + public void handleSpecific(Writer writer) throws IOException { + writer.write("specific"); } }