diff --git a/org.springframework.core/src/main/java/org/springframework/util/AntPathMatcher.java b/org.springframework.core/src/main/java/org/springframework/util/AntPathMatcher.java index 81a3539b368..3687daa7124 100644 --- a/org.springframework.core/src/main/java/org/springframework/util/AntPathMatcher.java +++ b/org.springframework.core/src/main/java/org/springframework/util/AntPathMatcher.java @@ -319,8 +319,7 @@ public class AntPathMatcher implements PathMatcher { } else { int dotPos1 = pattern1.indexOf('.'); - int dotPos2 = pattern2.indexOf('.'); - if (dotPos1 == -1 && dotPos2 == -1) { + if (dotPos1 == -1) { // simply concatenate the two patterns if (pattern1.endsWith("/") || pattern2.startsWith("/")) { return pattern1 + pattern2; @@ -329,25 +328,20 @@ public class AntPathMatcher implements PathMatcher { return pattern1 + "/" + pattern2; } } - String fileName1 = ""; - String extension1 = ""; - if (dotPos1 != -1) { - fileName1 = pattern1.substring(0, dotPos1); - extension1 = pattern1.substring(dotPos1); - } - else { - fileName1 = pattern1; - } - String fileName2 = ""; - String extension2 = ""; + String fileName1 = pattern1.substring(0, dotPos1); + String extension1 = pattern1.substring(dotPos1); + String fileName2; + String extension2; + int dotPos2 = pattern2.indexOf('.'); if (dotPos2 != -1) { fileName2 = pattern2.substring(0, dotPos2); extension2 = pattern2.substring(dotPos2); } else { fileName2 = pattern2; + extension2 = ""; } - String fileName = fileName1.endsWith("*") ? fileName2 : fileName2; + String fileName = fileName1.endsWith("*") ? fileName2 : fileName1; String extension = extension1.startsWith("*") ? extension2 : extension1; return fileName + extension; diff --git a/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java b/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java index 4bf087e3b36..7681d374498 100644 --- a/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java +++ b/org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java @@ -348,6 +348,7 @@ public class AntPathMatcherTests { assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels/*", "{hotel}")); assertEquals("/hotels/**/{hotel}", pathMatcher.combine("/hotels/**", "{hotel}")); assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels", "{hotel}")); + assertEquals("/hotels/{hotel}.*", pathMatcher.combine("/hotels", "{hotel}.*")); assertEquals("/hotels/*/booking/{booking}", pathMatcher.combine("/hotels/*/booking", "{booking}")); assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel.html")); assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel")); 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 0f4bda10e09..5ba30a4d49e 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 @@ -399,11 +399,11 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen boolean match = false; if (mappingInfo.paths.length > 0) { List matchedPaths = new ArrayList(mappingInfo.paths.length); - for (String mappedPath : mappingInfo.paths) { - if (isPathMatch(mappedPath, lookupPath)) { + for (String methodLevelPattern : mappingInfo.paths) { + if (isPathMatch(methodLevelPattern, lookupPath)) { if (checkParameters(mappingInfo, request)) { match = true; - matchedPaths.add(mappedPath); + matchedPaths.add(methodLevelPattern); } else { for (RequestMethod requestMethod : mappingInfo.methods) { @@ -479,17 +479,31 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen } } - private boolean isPathMatch(String mappedPath, String lookupPath) { - if (mappedPath.equals(lookupPath) || pathMatcher.match(mappedPath, lookupPath)) { + private boolean isPathMatch(String methodLevelPattern, String lookupPath) { + if (isPathMatchInternal(methodLevelPattern, lookupPath)) { return true; } - boolean hasSuffix = (mappedPath.indexOf('.') != -1); - if (!hasSuffix && pathMatcher.match(mappedPath + ".*", lookupPath)) { + if (hasTypeLevelMapping()) { + String[] typeLevelPatterns = getTypeLevelMapping().value(); + for (String typeLevelPattern : typeLevelPatterns) { + if (!typeLevelPattern.startsWith("/")) { + typeLevelPattern = "/" + typeLevelPattern; + } + String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern); + if (isPathMatchInternal(combinedPattern, lookupPath)) { + return true; + } + } + + } + return false; + } + + private boolean isPathMatchInternal(String pattern, String lookupPath) { + if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) { return true; } - return (!mappedPath.startsWith("/") && - (lookupPath.endsWith(mappedPath) || pathMatcher.match("/**/" + mappedPath, lookupPath) || - (!hasSuffix && pathMatcher.match("/**/" + mappedPath + ".*", lookupPath)))); + return !(pattern.indexOf('.') != -1) && pathMatcher.match(pattern + ".*", lookupPath); } private boolean checkParameters(RequestMappingInfo mapping, HttpServletRequest request) { 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 d18818dfe3a..fd87705ddf3 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 @@ -24,7 +24,6 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletResponse; import static org.junit.Assert.*; -import org.junit.Ignore; import org.junit.Test; import org.springframework.beans.BeansException; @@ -145,24 +144,33 @@ public class UriTemplateServletAnnotationControllerTests { } @Test - @Ignore("In progress") public void crud() throws Exception { initServlet(CrudController.class); MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels"); MockHttpServletResponse response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("getHotels", response.getContentAsString()); + assertEquals("list", response.getContentAsString()); request = new MockHttpServletRequest("POST", "/hotels"); response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("newHotel", response.getContentAsString()); + assertEquals("create", response.getContentAsString()); - request = new MockHttpServletRequest("POST", "/hotels"); + request = new MockHttpServletRequest("GET", "/hotels/42"); response = new MockHttpServletResponse(); servlet.service(request, response); - assertEquals("newHotel", response.getContentAsString()); + assertEquals("show-42", response.getContentAsString()); + + request = new MockHttpServletRequest("PUT", "/hotels/42"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("createOrUpdate-42", response.getContentAsString()); + + request = new MockHttpServletRequest("DELETE", "/hotels/42"); + response = new MockHttpServletResponse(); + servlet.service(request, response); + assertEquals("remove-42", response.getContentAsString()); } private void initServlet(final Class controllerclass) throws ServletException {