From e1afab94de7cbffc73a9820e0c5332389f6f9772 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Tue, 12 Jan 2016 09:49:02 +0100 Subject: [PATCH] #269 - Polishing. Simplified slash removal and made sure slashes occuring multiple times are removed properly. Original pull request: #423. --- .../core/AnnotationMappingDiscoverer.java | 34 +++++++++++-------- .../AnnotationMappingDiscovererUnitTest.java | 23 +++++++++++-- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/core/AnnotationMappingDiscoverer.java b/src/main/java/org/springframework/hateoas/core/AnnotationMappingDiscoverer.java index dfe3818c..619353fd 100644 --- a/src/main/java/org/springframework/hateoas/core/AnnotationMappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/core/AnnotationMappingDiscoverer.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -19,6 +19,7 @@ import static org.springframework.core.annotation.AnnotationUtils.*; import java.lang.annotation.Annotation; import java.lang.reflect.Method; +import java.util.regex.Pattern; import org.springframework.util.Assert; @@ -29,6 +30,8 @@ import org.springframework.util.Assert; */ public class AnnotationMappingDiscoverer implements MappingDiscoverer { + private static final Pattern MULTIPLE_SLASHES = Pattern.compile("\\/{2,}"); + private final Class annotationType; private final String mappingAttributeName; @@ -68,8 +71,8 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { String[] mapping = getMappingFrom(findAnnotation(type, annotationType)); if (mapping.length > 1) { - throw new IllegalStateException(String.format("Multiple class level mappings defined on class %s!", - type.getName())); + throw new IllegalStateException( + String.format("Multiple class level mappings defined on class %s!", type.getName())); } return mapping.length == 0 ? null : mapping[0]; @@ -99,8 +102,8 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { String[] mapping = getMappingFrom(findAnnotation(method, annotationType)); if (mapping.length > 1) { - throw new IllegalStateException(String.format("Multiple method level mappings defined on method %s!", - method.toString())); + throw new IllegalStateException( + String.format("Multiple method level mappings defined on method %s!", method.toString())); } String typeMapping = getMapping(type); @@ -112,16 +115,6 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { return typeMapping == null || "/".equals(typeMapping) ? mapping[0] : join(typeMapping, mapping[0]); } - private String join(String typeMapping, String mapping) { - StringBuilder builder = new StringBuilder(); - - builder.append(typeMapping.endsWith("/") ? typeMapping.substring(0, typeMapping.length() - 1) : typeMapping); - builder.append('/'); - builder.append(mapping.startsWith("/") ? mapping.substring(1) : mapping); - - return builder.toString(); - } - private String[] getMappingFrom(Annotation annotation) { Object value = mappingAttributeName == null ? getValue(annotation) : getValue(annotation, mappingAttributeName); @@ -137,4 +130,15 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { throw new IllegalStateException(String.format( "Unsupported type for the mapping attribute! Support String and String[] but got %s!", value.getClass())); } + + /** + * Joins the given mappings making sure exactly one slash. + * + * @param typeMapping must not be {@literal null} or empty. + * @param mapping must not be {@literal null} or empty. + * @return + */ + private static String join(String typeMapping, String mapping) { + return MULTIPLE_SLASHES.matcher(typeMapping.concat("/").concat(mapping)).replaceAll("/"); + } } diff --git a/src/test/java/org/springframework/hateoas/core/AnnotationMappingDiscovererUnitTest.java b/src/test/java/org/springframework/hateoas/core/AnnotationMappingDiscovererUnitTest.java index 3b5e3beb..b8d427df 100644 --- a/src/test/java/org/springframework/hateoas/core/AnnotationMappingDiscovererUnitTest.java +++ b/src/test/java/org/springframework/hateoas/core/AnnotationMappingDiscovererUnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2014 the original author or authors. + * Copyright 2012-2016 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. @@ -21,14 +21,13 @@ import static org.junit.Assert.*; import java.lang.reflect.Method; import org.junit.Test; -import org.springframework.http.HttpEntity; import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; /** * Unit tests for {@link AnnotationMappingDiscoverer}. * * @author Oliver Gierke + * @author Kevin Conaway */ public class AnnotationMappingDiscovererUnitTest { @@ -118,6 +117,17 @@ public class AnnotationMappingDiscovererUnitTest { assertThat(discoverer.getMapping(method), is("trailing/withslash")); } + /** + * @see #269 + */ + @Test + public void removesMultipleSlashes() throws Exception { + + Method method = ControllerWithMultipleSlashes.class.getMethod("withslash"); + + assertThat(discoverer.getMapping(method), is("trailing/withslash")); + } + @RequestMapping("/type") interface MyController { @@ -180,4 +190,11 @@ public class AnnotationMappingDiscovererUnitTest { @RequestMapping("/withslash") void withslash(); } + + @RequestMapping("trailing///") + interface ControllerWithMultipleSlashes { + + @RequestMapping("////withslash") + void withslash(); + } }