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 d0916c2aaa..8441928619 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -430,10 +430,19 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
return mav;
}
+ /**
+ * This method always returns -1 since an annotated controller can have many methods,
+ * each requiring separate lastModified calculations. Instead, an
+ * @{@link RequestMapping}-annotated method can calculate the lastModified value, call
+ * {@link org.springframework.web.context.request.WebRequest#checkNotModified(long)}
+ * to check it, and return {@code null} if that returns {@code true}.
+ * @see org.springframework.web.context.request.WebRequest#checkNotModified(long)
+ */
public long getLastModified(HttpServletRequest request, Object handler) {
return -1;
}
+
/**
* Build a HandlerMethodResolver for the given handler type.
*/
@@ -463,8 +472,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
* @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest)
* @see ServletRequestDataBinder#convertIfNecessary(Object, Class, org.springframework.core.MethodParameter)
*/
- protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName)
- throws Exception {
+ protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) throws Exception {
return new ServletRequestDataBinder(target, objectName);
}
@@ -620,21 +628,20 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
else {
if (!allowedMethods.isEmpty()) {
- throw new HttpRequestMethodNotSupportedException(request.getMethod(),
- StringUtils.toStringArray(allowedMethods));
+ throw new HttpRequestMethodNotSupportedException(request.getMethod(), StringUtils.toStringArray(allowedMethods));
}
- throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(),
- request.getParameterMap());
+ throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), request.getParameterMap());
}
}
/**
* Determines the combined pattern for the given methodLevelPattern and path.
- *
Uses the following algorithm:
+ * Uses the following algorithm:
+ *
* - If there is a type-level mapping with path information, it is {@linkplain
* PathMatcher#combine(String, String) combined} with the method-level pattern.
- * - If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the
- * request, it is combined with the method-level pattern.
+ * - If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern}
+ * in the request, it is combined with the method-level pattern.
* - Otherwise, the method-level pattern is returned.
*
*/
@@ -646,8 +653,9 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
typeLevelPattern = "/" + typeLevelPattern;
}
String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern);
- if (isPathMatchInternal(combinedPattern, lookupPath)) {
- return combinedPattern;
+ String matchingPattern = getMatchingPattern(combinedPattern, lookupPath);
+ if (matchingPattern != null) {
+ return matchingPattern;
}
}
return null;
@@ -655,44 +663,44 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) {
String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern);
- if (!combinedPattern.equals(bestMatchingPattern) &&
- (isPathMatchInternal(combinedPattern, lookupPath))) {
- return combinedPattern;
+ String matchingPattern = getMatchingPattern(combinedPattern, lookupPath);
+ if (matchingPattern != null && !matchingPattern.equals(bestMatchingPattern)) {
+ return matchingPattern;
}
}
- if (isPathMatchInternal(methodLevelPattern, lookupPath)) {
- return methodLevelPattern;
+ return getMatchingPattern(methodLevelPattern, lookupPath);
+ }
+
+ private String getMatchingPattern(String pattern, String lookupPath) {
+ if (pattern.equals(lookupPath)) {
+ return pattern;
+ }
+ boolean hasSuffix = pattern.indexOf('.') != -1;
+ if (!hasSuffix) {
+ String patternWithSuffix = pattern + ".*";
+ if (pathMatcher.match(patternWithSuffix, lookupPath)) {
+ return patternWithSuffix;
+ }
+ }
+ if (pathMatcher.match(pattern, lookupPath)) {
+ return pattern;
+ }
+ boolean endsWithSlash = pattern.endsWith("/");
+ if (!endsWithSlash) {
+ String patternWithSlash = pattern + "/";
+ if (pathMatcher.match(patternWithSlash, lookupPath)) {
+ return patternWithSlash;
+ }
}
return null;
}
- private boolean isPathMatchInternal(String pattern, String lookupPath) {
- if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) {
- return true;
- }
- boolean hasSuffix = pattern.indexOf('.') != -1;
- if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) {
- return true;
- }
- boolean endsWithSlash = pattern.endsWith("/");
- if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) {
- return true;
- }
- return false;
- }
-
@SuppressWarnings("unchecked")
- private void extractHandlerMethodUriTemplates(String mappedPattern,
- String lookupPath,
- HttpServletRequest request) {
-
+ private void extractHandlerMethodUriTemplates(String mappedPattern, String lookupPath, HttpServletRequest request) {
Map variables =
(Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
-
int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{");
-
- if ( (variables == null || patternVariableCount != variables.size())
- && pathMatcher.match(mappedPattern, lookupPath)) {
+ if ((variables == null || patternVariableCount != variables.size()) && pathMatcher.match(mappedPattern, lookupPath)) {
variables = pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath);
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 2b436092e3..e5edf988d8 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
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2010 the original author or authors.
+ * Copyright 2002-2011 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.
@@ -23,7 +23,6 @@ import java.util.Date;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletResponse;
-import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.beans.BeansException;
@@ -43,7 +42,12 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.support.ControllerClassNameHandlerMapping;
-/** @author Arjen Poutsma */
+import static org.junit.Assert.*;
+
+/**
+ * @author Arjen Poutsma
+ * @author Rossen Stoyanchev
+ */
public class UriTemplateServletAnnotationControllerTests {
private DispatcherServlet servlet;
@@ -309,9 +313,7 @@ public class UriTemplateServletAnnotationControllerTests {
assertEquals("test-42", response.getContentAsString());
}
- /*
- * See SPR-6640
- */
+ // SPR-6640
@Test
public void menuTree() throws Exception {
initServlet(MenuTreeController.class);
@@ -322,9 +324,7 @@ public class UriTemplateServletAnnotationControllerTests {
assertEquals("M5", response.getContentAsString());
}
- /*
- * See SPR-6876
- */
+ // SPR-6876
@Test
public void variableNames() throws Exception {
initServlet(VariableNamesController.class);
@@ -340,9 +340,18 @@ public class UriTemplateServletAnnotationControllerTests {
assertEquals("bar-bar", response.getContentAsString());
}
- /*
- * See SPR-6906
- */
+ // SPR-8543
+ @Test
+ public void variableNamesWithUrlExtension() throws Exception {
+ initServlet(VariableNamesController.class);
+
+ MockHttpServletRequest request = new MockHttpServletRequest("GET", "/test/foo.json");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+ servlet.service(request, response);
+ assertEquals("foo-foo", response.getContentAsString());
+ }
+
+ // SPR-6906
@Test
public void controllerClassName() throws Exception {
servlet = new DispatcherServlet() {
@@ -376,9 +385,7 @@ public class UriTemplateServletAnnotationControllerTests {
assertEquals("plain-bar", response.getContentAsString());
}
- /*
- * See SPR-6978
- */
+ // SPR-6978
@Test
public void doIt() throws Exception {
initServlet(Spr6978Controller.class);
@@ -406,10 +413,7 @@ public class UriTemplateServletAnnotationControllerTests {
}
-
- /*
- * Controllers
- */
+ // Controllers
@Controller
public static class SimpleUriTemplateController {
@@ -548,7 +552,6 @@ public class UriTemplateServletAnnotationControllerTests {
}
-
@Controller
@RequestMapping("hotels")
public static class CrudController {
@@ -676,5 +679,4 @@ public class UriTemplateServletAnnotationControllerTests {
}
}
-
}