From 6473c10113feb31ce386bd5f224209bab2ae2403 Mon Sep 17 00:00:00 2001 From: Kamill Sokol Date: Sun, 18 May 2014 12:21:34 +0100 Subject: [PATCH] #96 - Fixed double-encoding issues in LinkBuilderSupport. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit LinkBuilderSupport now prefers the URI string over the URI to avoid double encoding issues. VndErrorsMarshallingTest.jackson2marshalling(…) shouldn't take line breaks into account due to platform differences (Win, OSX, Linux) Original pull request: #179. --- .../hateoas/core/LinkBuilderSupport.java | 8 ++++- .../hateoas/jaxrs/JaxRsLinkBuilder.java | 10 ++++--- .../hateoas/mvc/ControllerLinkBuilder.java | 10 +++++-- .../mvc/ControllerLinkBuilderFactory.java | 3 +- .../hateoas/VndErrorsMarshallingTest.java | 5 ++-- .../core/LinkBuilderSupportUnitTest.java | 5 +++- .../JaxRsLinkBuilderFactoryUnitTest.java | 28 +++++++++++++++++ .../ControllerLinkBuilderFactoryUnitTest.java | 30 +++++++++++++++++-- .../mvc/ControllerLinkBuilderUnitTest.java | 12 ++++++++ 9 files changed, 96 insertions(+), 15 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/core/LinkBuilderSupport.java b/src/main/java/org/springframework/hateoas/core/LinkBuilderSupport.java index dd62773d..ec30bec3 100644 --- a/src/main/java/org/springframework/hateoas/core/LinkBuilderSupport.java +++ b/src/main/java/org/springframework/hateoas/core/LinkBuilderSupport.java @@ -15,6 +15,8 @@ */ package org.springframework.hateoas.core; +import static org.springframework.web.util.UriComponentsBuilder.*; + import java.net.URI; import org.springframework.hateoas.Identifiable; @@ -30,6 +32,7 @@ import org.springframework.web.util.UriComponentsBuilder; * * @author Ricardo Gladwell * @author Oliver Gierke + * @author Kamill Sokol */ public abstract class LinkBuilderSupport implements LinkBuilder { @@ -70,8 +73,11 @@ public abstract class LinkBuilderSupport implements LinkB return getThis(); } + String uriString = uriComponents.toUriString(); + UriComponentsBuilder builder = uriString.isEmpty() ? fromUri(uriComponents.toUri()) + : fromUriString(uriString); + UriComponents components = UriComponentsBuilder.fromUriString(path).build(); - UriComponentsBuilder builder = UriComponentsBuilder.fromUri(uriComponents.toUri()); for (String pathSegment : components.getPathSegments()) { builder.pathSegment(pathSegment); diff --git a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java index a6d51992..d9adab63 100644 --- a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 the original author or authors. + * Copyright 2012-2014 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. @@ -22,13 +22,14 @@ import org.springframework.hateoas.core.AnnotationMappingDiscoverer; import org.springframework.hateoas.core.LinkBuilderSupport; import org.springframework.hateoas.core.MappingDiscoverer; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; -import org.springframework.web.util.UriTemplate; /** * {@link LinkBuilder} to derive URI mappings from a JAX-RS {@link Path} annotation. * * @author Oliver Gierke + * @author Kamill Sokol */ public class JaxRsLinkBuilder extends LinkBuilderSupport { @@ -66,8 +67,9 @@ public class JaxRsLinkBuilder extends LinkBuilderSupport { JaxRsLinkBuilder builder = new JaxRsLinkBuilder(ServletUriComponentsBuilder.fromCurrentServletMapping()); - UriTemplate template = new UriTemplate(DISCOVERER.getMapping(service)); - return builder.slash(template.expand(parameters)); + UriComponents uriComponents = UriComponentsBuilder.fromUriString(DISCOVERER.getMapping(service)).build(); + UriComponents expandedComponents = uriComponents.expand(parameters); + return builder.slash(expandedComponents); } /* diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java index 9e74e3d7..d36f3f4d 100755 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2014 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. @@ -32,6 +32,7 @@ import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.servlet.support.ServletUriComponentsBuilder; +import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import org.springframework.web.util.UriTemplate; @@ -39,6 +40,7 @@ import org.springframework.web.util.UriTemplate; * Builder to ease building {@link Link} instances pointing to Spring MVC controllers. * * @author Oliver Gierke + * @author Kamill Sokol */ public class ControllerLinkBuilder extends LinkBuilderSupport { @@ -79,9 +81,11 @@ public class ControllerLinkBuilder extends LinkBuilderSupport { @@ -133,7 +134,7 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory { diff --git a/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java index f65447ee..83f5f21c 100644 --- a/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java @@ -1,3 +1,18 @@ +/* + * Copyright 2011-2014 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. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ package org.springframework.hateoas.jaxrs; import static org.hamcrest.Matchers.*; @@ -14,6 +29,7 @@ import org.springframework.hateoas.TestUtils; * * @author Ricardo Gladwell * @author Oliver Gierke + * @author Kamill Sokol */ public class JaxRsLinkBuilderFactoryUnitTest extends TestUtils { @@ -37,6 +53,18 @@ public class JaxRsLinkBuilderFactoryUnitTest extends TestUtils { assertThat(link.getHref(), endsWith("/people/15/addresses")); } + /** + * @see #96 + */ + @Test + public void createsLinkToParameterizedServiceRootWithUrlEncoding() { + + Link link = factory.linkTo(PersonsAddressesService.class, "with blank").withSelfRel(); + + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/people/with%20blank/addresses")); + } + @Path("/people") interface PersonService { diff --git a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java index abfc9ec9..7e050373 100644 --- a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2013 the original author or authors. + * Copyright 2012-2014 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. @@ -17,7 +17,7 @@ package org.springframework.hateoas.mvc; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; -import static org.springframework.hateoas.core.DummyInvocationUtils.*; +import static org.springframework.hateoas.mvc.ControllerLinkBuilder.*; import java.util.Arrays; @@ -29,6 +29,7 @@ import org.springframework.format.annotation.DateTimeFormat; import org.springframework.format.annotation.DateTimeFormat.ISO; import org.springframework.hateoas.Link; import org.springframework.hateoas.TestUtils; +import org.springframework.hateoas.mvc.ControllerLinkBuilderUnitTest.ControllerWithMethods; import org.springframework.hateoas.mvc.ControllerLinkBuilderUnitTest.PersonControllerImpl; import org.springframework.hateoas.mvc.ControllerLinkBuilderUnitTest.PersonsAddressesController; import org.springframework.http.HttpEntity; @@ -41,6 +42,7 @@ import org.springframework.web.util.UriComponentsBuilder; * * @author Ricardo Gladwell * @author Oliver Gierke + * @author Kamill Sokol */ public class ControllerLinkBuilderFactoryUnitTest extends TestUtils { @@ -93,6 +95,30 @@ public class ControllerLinkBuilderFactoryUnitTest extends TestUtils { assertThat(link.getHref(), endsWith("/sample/" + ISODateTimeFormat.date().print(now))); } + /** + * @see #96 + */ + @Test + public void linksToMethodWithPathVariableContainingBlank() { + + Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable("with blank")).withSelfRel(); + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/something/with%20blank/foo")); + } + + /** + * @see #96 + */ + @Test + public void createsLinkToParameterizedControllerRootContainingBlank() { + + Link link = factory.linkTo(PersonsAddressesController.class, "with blank").withSelfRel(); + + assertPointsToMockServer(link); + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/people/with%20blank/addresses")); + } + static interface SampleController { @RequestMapping("/sample/{id}") diff --git a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java index 3cb36a9a..1fac26d6 100644 --- a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderUnitTest.java @@ -42,6 +42,7 @@ import org.springframework.web.util.UriComponentsBuilder; * * @author Oliver Gierke * @author Dietrich Schulten + * @author Kamill Sokol */ public class ControllerLinkBuilderUnitTest extends TestUtils { @@ -343,6 +344,17 @@ public class ControllerLinkBuilderUnitTest extends TestUtils { assertThat(link.getHref(), endsWith("/child/parent")); } + /** + * @see #96 + */ + @Test + public void linksToMethodWithPathVariableContainingBlank() { + + Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPathVariable("with blank")).withSelfRel(); + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/something/with%20blank/foo")); + } + private static UriComponents toComponents(Link link) { return UriComponentsBuilder.fromUriString(link.getHref()).build(); }