diff --git a/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java b/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java index 187886aa..97d0f38b 100644 --- a/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java @@ -24,6 +24,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; +import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.http.HttpMethod; @@ -43,6 +44,7 @@ import org.springframework.web.bind.annotation.RequestMethod; public class AnnotationMappingDiscoverer implements MappingDiscoverer { private static final Pattern MULTIPLE_SLASHES = Pattern.compile("/{2,}"); + private static final Pattern TEMPLATE_VARIABLE_NAME = Pattern.compile("\\{(.*)\\}"); private final Class annotationType; private final String mappingAttributeName; @@ -116,7 +118,7 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { return typeMapping; } - return typeMapping == null || "/".equals(typeMapping) ? mapping[0] : join(typeMapping, mapping[0]); + return cleanup(typeMapping == null || "/".equals(typeMapping) ? mapping[0] : join(typeMapping, mapping[0])); } /** @@ -179,6 +181,49 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { * @return */ private static String join(String typeMapping, String mapping) { - return MULTIPLE_SLASHES.matcher(typeMapping.concat("/").concat(mapping)).replaceAll("/"); + return typeMapping.concat("/").concat(mapping); + } + + /** + * @param mapping + * @return + */ + private static String cleanup(String mapping) { + + String[] parts = mapping.split("/"); + StringBuilder result = new StringBuilder(); + + for (int i = 0; i < parts.length; i++) { + + String part = parts[i]; + + if (i != 0) { + result.append("/"); + } + + result.append(part.contains(":") ? cleanupPart(part) : part); + } + + return MULTIPLE_SLASHES.matcher(result.toString()).replaceAll("/"); + } + + private static String cleanupPart(String variable) { + + if (!variable.contains("{")) { + return variable; + } + + Matcher matcher = TEMPLATE_VARIABLE_NAME.matcher(variable); + + if (!matcher.find()) { + return variable; + } + + String rawName = matcher.group(1); + int colonIndex = rawName.indexOf(':'); + + return colonIndex < 0 + ? variable + : variable.replace(matcher.group(0), "{" + rawName.substring(0, colonIndex) + "}"); } } diff --git a/src/test/java/org/springframework/hateoas/server/core/AnnotationMappingDiscovererUnitTest.java b/src/test/java/org/springframework/hateoas/server/core/AnnotationMappingDiscovererUnitTest.java index 0834a74f..ce4fc59c 100755 --- a/src/test/java/org/springframework/hateoas/server/core/AnnotationMappingDiscovererUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/core/AnnotationMappingDiscovererUnitTest.java @@ -25,7 +25,7 @@ import org.springframework.web.bind.annotation.RequestMapping; /** * Unit tests for {@link AnnotationMappingDiscoverer}. - * + * * @author Oliver Gierke * @author Kevin Conaway * @author Mark Paluch @@ -153,6 +153,13 @@ class AnnotationMappingDiscovererUnitTest { assertThat(discoverer.getMapping(method)).isEqualTo("/type/otherMethod"); } + @Test // #1412 + void removesMatchingExpressionFromTemplateVariable() throws Exception { + + Method method = MyController.class.getMethod("mappingWithMatchingExpression"); + assertThat(discoverer.getMapping(method)).isEqualTo("/type/foo/{bar}"); + } + @RequestMapping("/type") interface MyController { @@ -164,6 +171,9 @@ class AnnotationMappingDiscovererUnitTest { @RequestMapping void noMethodMapping(); + + @RequestMapping("/foo/{bar:[ABC]{1}}") + void mappingWithMatchingExpression(); } interface ControllerWithoutTypeLevelMapping { diff --git a/src/test/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscovererUnitTest.java b/src/test/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscovererUnitTest.java index dc466889..fe19b3ad 100755 --- a/src/test/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscovererUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscovererUnitTest.java @@ -24,8 +24,6 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.hateoas.TestUtils; -import org.springframework.hateoas.server.core.AnnotationMappingDiscoverer; -import org.springframework.hateoas.server.core.PropertyResolvingMappingDiscoverer; import org.springframework.mock.web.MockServletContext; import org.springframework.test.context.TestPropertySource; import org.springframework.test.context.junit.jupiter.web.SpringJUnitWebConfig;