diff --git a/src/main/java/org/springframework/hateoas/LinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/LinkBuilderFactory.java index 9b273e83..6a09a66f 100644 --- a/src/main/java/org/springframework/hateoas/LinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/LinkBuilderFactory.java @@ -15,6 +15,8 @@ */ package org.springframework.hateoas; +import java.util.Map; + /** * Factory for {@link LinkBuilder} instances. * @@ -41,4 +43,15 @@ public interface LinkBuilderFactory { * @return */ T linkTo(Class target, Object... parameters); + + /** + * Creates a new {@link LinkBuilder} with a base of the mapping annotated to the given target class (controller, + * service, etc.). Parameter map is used to fill up potentially available path variables in the class scope request + * mapping. + * + * @param target must not be {@literal null}. + * @param parameters must not be {@literal null}. + * @return + */ + T linkTo(Class target, Map parameters); } diff --git a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java index d9adab63..b2492169 100644 --- a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilder.java @@ -25,6 +25,8 @@ import org.springframework.web.servlet.support.ServletUriComponentsBuilder; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; +import java.util.Map; + /** * {@link LinkBuilder} to derive URI mappings from a JAX-RS {@link Path} annotation. * @@ -72,6 +74,24 @@ public class JaxRsLinkBuilder extends LinkBuilderSupport { return builder.slash(expandedComponents); } + /** + * Creates a new {@link JaxRsLinkBuilder} instance to link to the {@link Path} mapping tied to the given class binding + * the given parameters to the URI template. + * + * @param service the class to discover the annotation on, must not be {@literal null}. + * @param parameters map of additional parameters to bind to the URI template declared in the annotation, must not be + * {@literal null}. + * @return + */ + public static JaxRsLinkBuilder linkTo(Class service, Map parameters) { + + JaxRsLinkBuilder builder = new JaxRsLinkBuilder(ServletUriComponentsBuilder.fromCurrentServletMapping()); + + UriComponents uriComponents = UriComponentsBuilder.fromUriString(DISCOVERER.getMapping(service)).build(); + UriComponents expandedComponents = uriComponents.expand(parameters); + return builder.slash(expandedComponents); + } + /* * (non-Javadoc) * @see org.springframework.hateoas.UriComponentsLinkBuilder#getThis() diff --git a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactory.java index 7a7f70da..30930dd1 100644 --- a/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactory.java @@ -18,6 +18,8 @@ package org.springframework.hateoas.jaxrs; import org.springframework.hateoas.LinkBuilder; import org.springframework.hateoas.LinkBuilderFactory; +import java.util.Map; + /** * Factory for {@link LinkBuilder} instances based on the path mapping annotated on the given JAX-RS service. * @@ -42,4 +44,13 @@ public class JaxRsLinkBuilderFactory implements LinkBuilderFactory service, Object... parameters) { return JaxRsLinkBuilder.linkTo(service, parameters); } + + /* + * (non-Javadoc) + * @see org.springframework.hateoas.LinkBuilderFactory#linkTo(java.lang.Class, java.util.Map) + */ + @Override + public JaxRsLinkBuilder linkTo(Class service, Map parameters) { + return JaxRsLinkBuilder.linkTo(service, parameters); + } } diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java index 90f8a9bf..053b8a7d 100755 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilder.java @@ -19,6 +19,7 @@ import static org.springframework.util.StringUtils.*; import java.lang.reflect.Method; import java.net.URI; +import java.util.Map; import javax.servlet.http.HttpServletRequest; @@ -101,11 +102,34 @@ public class ControllerLinkBuilder extends LinkBuilderSupport controller, Map parameters) { + + Assert.notNull(controller); + + ControllerLinkBuilder builder = new ControllerLinkBuilder(getBuilder()); + String mapping = DISCOVERER.getMapping(controller); + + UriComponents uriComponents = UriComponentsBuilder.fromUriString(mapping == null ? "/" : mapping).build(); + UriComponents expandedComponents = uriComponents.expand(parameters); + + return builder.slash(expandedComponents); + } + /* * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(Method, Object...) */ public static ControllerLinkBuilder linkTo(Method method, Object... parameters) { - return linkTo(method.getDeclaringClass(), method, parameters); + return linkTo(method.getDeclaringClass(), method, parameters); } /* diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java index ba3d7a19..1c3084bc 100644 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java @@ -95,6 +95,15 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory controller, Map parameters) { + return ControllerLinkBuilder.linkTo(controller, parameters); + } + /* * (non-Javadoc) * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Class, java.lang.reflect.Method, java.lang.Object[]) diff --git a/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java index 83f5f21c..d49511f2 100644 --- a/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/jaxrs/JaxRsLinkBuilderFactoryUnitTest.java @@ -24,6 +24,9 @@ import org.junit.Test; import org.springframework.hateoas.Link; import org.springframework.hateoas.TestUtils; +import java.util.LinkedHashMap; +import java.util.Map; + /** * Unit test for {@link JaxRsLinkBuilderFactory}. * @@ -65,6 +68,17 @@ public class JaxRsLinkBuilderFactoryUnitTest extends TestUtils { assertThat(link.getHref(), endsWith("/people/with%20blank/addresses")); } + @Test + public void createsLinkToParameterizedServiceRootWithParameterMap() { + Map pathParams = new LinkedHashMap(); + pathParams.put("id", "17"); + + Link link = factory.linkTo(PersonsAddressesService.class, pathParams).withSelfRel(); + + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/people/17/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 c8f11bcf..9c8c0734 100644 --- a/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactoryUnitTest.java @@ -74,6 +74,18 @@ public class ControllerLinkBuilderFactoryUnitTest extends TestUtils { assertThat(link.getHref(), endsWith("/people/15/addresses")); } + @Test + public void createsLinkToParameterizedControllerRootWithParameterMap() { + Map pathParams = new LinkedHashMap(); + pathParams.put("id", "17"); + + Link link = factory.linkTo(PersonsAddressesController.class, pathParams).withSelfRel(); + + assertPointsToMockServer(link); + assertThat(link.getRel(), is(Link.REL_SELF)); + assertThat(link.getHref(), endsWith("/people/17/addresses")); + } + @Test public void appliesParameterValueIfContributorConfigured() {