Skip to content

Commit acc8492

Browse files
committed
SPR-5631 - Implicit /** mapping on type-level @RequestMapping
1 parent 02e96e0 commit acc8492

File tree

4 files changed

+47
-30
lines changed

4 files changed

+47
-30
lines changed

org.springframework.core/src/main/java/org/springframework/util/AntPathMatcher.java

+8-14
Original file line numberDiff line numberDiff line change
@@ -319,8 +319,7 @@ else if (pattern1.endsWith("/**")) {
319319
}
320320
else {
321321
int dotPos1 = pattern1.indexOf('.');
322-
int dotPos2 = pattern2.indexOf('.');
323-
if (dotPos1 == -1 && dotPos2 == -1) {
322+
if (dotPos1 == -1) {
324323
// simply concatenate the two patterns
325324
if (pattern1.endsWith("/") || pattern2.startsWith("/")) {
326325
return pattern1 + pattern2;
@@ -329,25 +328,20 @@ else if (pattern1.endsWith("/**")) {
329328
return pattern1 + "/" + pattern2;
330329
}
331330
}
332-
String fileName1 = "";
333-
String extension1 = "";
334-
if (dotPos1 != -1) {
335-
fileName1 = pattern1.substring(0, dotPos1);
336-
extension1 = pattern1.substring(dotPos1);
337-
}
338-
else {
339-
fileName1 = pattern1;
340-
}
341-
String fileName2 = "";
342-
String extension2 = "";
331+
String fileName1 = pattern1.substring(0, dotPos1);
332+
String extension1 = pattern1.substring(dotPos1);
333+
String fileName2;
334+
String extension2;
335+
int dotPos2 = pattern2.indexOf('.');
343336
if (dotPos2 != -1) {
344337
fileName2 = pattern2.substring(0, dotPos2);
345338
extension2 = pattern2.substring(dotPos2);
346339
}
347340
else {
348341
fileName2 = pattern2;
342+
extension2 = "";
349343
}
350-
String fileName = fileName1.endsWith("*") ? fileName2 : fileName2;
344+
String fileName = fileName1.endsWith("*") ? fileName2 : fileName1;
351345
String extension = extension1.startsWith("*") ? extension2 : extension1;
352346

353347
return fileName + extension;

org.springframework.core/src/test/java/org/springframework/util/AntPathMatcherTests.java

+1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ public void combine() {
348348
assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels/*", "{hotel}"));
349349
assertEquals("/hotels/**/{hotel}", pathMatcher.combine("/hotels/**", "{hotel}"));
350350
assertEquals("/hotels/{hotel}", pathMatcher.combine("/hotels", "{hotel}"));
351+
assertEquals("/hotels/{hotel}.*", pathMatcher.combine("/hotels", "{hotel}.*"));
351352
assertEquals("/hotels/*/booking/{booking}", pathMatcher.combine("/hotels/*/booking", "{booking}"));
352353
assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel.html"));
353354
assertEquals("/hotel.html", pathMatcher.combine("/*.html", "/hotel"));

org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java

+24-10
Original file line numberDiff line numberDiff line change
@@ -399,11 +399,11 @@ public Method resolveHandlerMethod(HttpServletRequest request) throws ServletExc
399399
boolean match = false;
400400
if (mappingInfo.paths.length > 0) {
401401
List<String> matchedPaths = new ArrayList<String>(mappingInfo.paths.length);
402-
for (String mappedPath : mappingInfo.paths) {
403-
if (isPathMatch(mappedPath, lookupPath)) {
402+
for (String methodLevelPattern : mappingInfo.paths) {
403+
if (isPathMatch(methodLevelPattern, lookupPath)) {
404404
if (checkParameters(mappingInfo, request)) {
405405
match = true;
406-
matchedPaths.add(mappedPath);
406+
matchedPaths.add(methodLevelPattern);
407407
}
408408
else {
409409
for (RequestMethod requestMethod : mappingInfo.methods) {
@@ -479,17 +479,31 @@ public Method resolveHandlerMethod(HttpServletRequest request) throws ServletExc
479479
}
480480
}
481481

482-
private boolean isPathMatch(String mappedPath, String lookupPath) {
483-
if (mappedPath.equals(lookupPath) || pathMatcher.match(mappedPath, lookupPath)) {
482+
private boolean isPathMatch(String methodLevelPattern, String lookupPath) {
483+
if (isPathMatchInternal(methodLevelPattern, lookupPath)) {
484484
return true;
485485
}
486-
boolean hasSuffix = (mappedPath.indexOf('.') != -1);
487-
if (!hasSuffix && pathMatcher.match(mappedPath + ".*", lookupPath)) {
486+
if (hasTypeLevelMapping()) {
487+
String[] typeLevelPatterns = getTypeLevelMapping().value();
488+
for (String typeLevelPattern : typeLevelPatterns) {
489+
if (!typeLevelPattern.startsWith("/")) {
490+
typeLevelPattern = "/" + typeLevelPattern;
491+
}
492+
String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern);
493+
if (isPathMatchInternal(combinedPattern, lookupPath)) {
494+
return true;
495+
}
496+
}
497+
498+
}
499+
return false;
500+
}
501+
502+
private boolean isPathMatchInternal(String pattern, String lookupPath) {
503+
if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) {
488504
return true;
489505
}
490-
return (!mappedPath.startsWith("/") &&
491-
(lookupPath.endsWith(mappedPath) || pathMatcher.match("/**/" + mappedPath, lookupPath) ||
492-
(!hasSuffix && pathMatcher.match("/**/" + mappedPath + ".*", lookupPath))));
506+
return !(pattern.indexOf('.') != -1) && pathMatcher.match(pattern + ".*", lookupPath);
493507
}
494508

495509
private boolean checkParameters(RequestMappingInfo mapping, HttpServletRequest request) {

org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/annotation/UriTemplateServletAnnotationControllerTests.java

+14-6
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
import javax.servlet.http.HttpServletResponse;
2525

2626
import static org.junit.Assert.*;
27-
import org.junit.Ignore;
2827
import org.junit.Test;
2928

3029
import org.springframework.beans.BeansException;
@@ -145,24 +144,33 @@ public void implicitSubPath() throws Exception {
145144
}
146145

147146
@Test
148-
@Ignore("In progress")
149147
public void crud() throws Exception {
150148
initServlet(CrudController.class);
151149

152150
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/hotels");
153151
MockHttpServletResponse response = new MockHttpServletResponse();
154152
servlet.service(request, response);
155-
assertEquals("getHotels", response.getContentAsString());
153+
assertEquals("list", response.getContentAsString());
156154

157155
request = new MockHttpServletRequest("POST", "/hotels");
158156
response = new MockHttpServletResponse();
159157
servlet.service(request, response);
160-
assertEquals("newHotel", response.getContentAsString());
158+
assertEquals("create", response.getContentAsString());
161159

162-
request = new MockHttpServletRequest("POST", "/hotels");
160+
request = new MockHttpServletRequest("GET", "/hotels/42");
161+
response = new MockHttpServletResponse();
162+
servlet.service(request, response);
163+
assertEquals("show-42", response.getContentAsString());
164+
165+
request = new MockHttpServletRequest("PUT", "/hotels/42");
166+
response = new MockHttpServletResponse();
167+
servlet.service(request, response);
168+
assertEquals("createOrUpdate-42", response.getContentAsString());
169+
170+
request = new MockHttpServletRequest("DELETE", "/hotels/42");
163171
response = new MockHttpServletResponse();
164172
servlet.service(request, response);
165-
assertEquals("newHotel", response.getContentAsString());
173+
assertEquals("remove-42", response.getContentAsString());
166174
}
167175

168176
private void initServlet(final Class<?> controllerclass) throws ServletException {

0 commit comments

Comments
 (0)