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 78579c48..760575b1 100644 --- a/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/server/core/AnnotationMappingDiscoverer.java @@ -15,6 +15,7 @@ */ package org.springframework.hateoas.server.core; +import static java.util.Optional.ofNullable; import static org.springframework.core.annotation.AnnotatedElementUtils.*; import static org.springframework.core.annotation.AnnotationUtils.*; @@ -40,6 +41,7 @@ import org.springframework.web.bind.annotation.RequestMethod; * @author Oliver Gierke * @author Mark Paluch * @author Greg Turnquist + * @author Réda Housni Alaoui * @deprecated since 1.2, not for removal but for hiding within the package in 1.3 */ @Deprecated @@ -167,6 +169,14 @@ public class AnnotationMappingDiscoverer implements MappingDiscoverer { : Arrays.stream(mediaTypes).map(MediaType::parseMediaType).collect(Collectors.toList()); } + @Override + public String[] getParams(Method method) { + Annotation annotation = findMergedAnnotation(method, annotationType); + String[] params = (String[]) getValue(annotation, "params"); + + return ofNullable(params).orElseGet(() -> new String[0]); + } + private String[] getMappingFrom(@Nullable Annotation annotation) { if (annotation == null) { diff --git a/src/main/java/org/springframework/hateoas/server/core/CachingMappingDiscoverer.java b/src/main/java/org/springframework/hateoas/server/core/CachingMappingDiscoverer.java index 19415ea7..979e250f 100644 --- a/src/main/java/org/springframework/hateoas/server/core/CachingMappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/server/core/CachingMappingDiscoverer.java @@ -31,6 +31,7 @@ import org.springframework.util.StringUtils; * * @author Michal Stochmialek * @author Oliver Drotbohm + * @author Réda Housni Alaoui */ public class CachingMappingDiscoverer implements MappingDiscoverer { @@ -104,6 +105,11 @@ public class CachingMappingDiscoverer implements MappingDiscoverer { return delegate.getConsumes(method); } + @Override + public String[] getParams(Method method) { + return delegate.getParams(method); + } + private static String key(Class type, @Nullable Method method) { StringBuilder builder = new StringBuilder(type.getName()); diff --git a/src/main/java/org/springframework/hateoas/server/core/MappingDiscoverer.java b/src/main/java/org/springframework/hateoas/server/core/MappingDiscoverer.java index 966288a0..739fcf49 100644 --- a/src/main/java/org/springframework/hateoas/server/core/MappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/server/core/MappingDiscoverer.java @@ -29,6 +29,7 @@ import org.springframework.lang.Nullable; * * @author Oliver Gierke * @author Greg Turnquist + * @author Réda Housni Alaoui */ public interface MappingDiscoverer { @@ -79,4 +80,10 @@ public interface MappingDiscoverer { * @since 1.3 */ List getConsumes(Method method); + + /** + * @param method - must not be null. + * @return the parameters of the mapped request, narrowing the primary mapping. + */ + String[] getParams(Method method); } diff --git a/src/main/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscoverer.java b/src/main/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscoverer.java index 768fbf25..4f6cec5e 100644 --- a/src/main/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscoverer.java +++ b/src/main/java/org/springframework/hateoas/server/core/PropertyResolvingMappingDiscoverer.java @@ -31,6 +31,7 @@ import org.springframework.web.context.WebApplicationContext; * * @author Lars Michele * @author Oliver Drotbohm + * @author Réda Housni Alaoui */ class PropertyResolvingMappingDiscoverer implements MappingDiscoverer { @@ -91,6 +92,11 @@ class PropertyResolvingMappingDiscoverer implements MappingDiscoverer { return delegate.getConsumes(method); } + @Override + public String[] getParams(Method method) { + return delegate.getParams(method); + } + @Nullable private static String resolveProperties(@Nullable String mapping) { diff --git a/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java index 1f966a6a..26779b49 100644 --- a/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java @@ -24,9 +24,7 @@ import java.util.List; import java.util.Map; import java.util.function.Function; import java.util.function.Supplier; - import javax.servlet.ServletContext; - import org.springframework.core.MethodParameter; import org.springframework.core.convert.ConversionService; import org.springframework.format.support.DefaultFormattingConversionService; @@ -34,12 +32,15 @@ import org.springframework.hateoas.Link; import org.springframework.hateoas.server.MethodLinkBuilderFactory; import org.springframework.hateoas.server.core.LinkBuilderSupport; import org.springframework.hateoas.server.core.MethodParameters; +import org.springframework.hateoas.server.core.SpringAffordanceBuilder; import org.springframework.hateoas.server.core.WebHandler; import org.springframework.web.context.WebApplicationContext; 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.context.support.WebApplicationContextUtils; +import org.springframework.web.servlet.mvc.condition.NameValueExpression; +import org.springframework.web.servlet.mvc.condition.ParamsRequestCondition; import org.springframework.web.util.UriComponentsBuilder; /** @@ -54,6 +55,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Kevin Conaway * @author Andrew Naydyonock * @author Greg Turnquist + * @author Réda Housni Alaoui */ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory { @@ -120,6 +122,19 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory { + String[] primaryParams = SpringAffordanceBuilder.DISCOVERER.getParams(invocation.getMethod()); + ParamsRequestCondition paramsRequestCondition = new ParamsRequestCondition(primaryParams); + for (NameValueExpression expression: paramsRequestCondition.getExpressions()) { + if (expression.isNegated()) { + continue; + } + String value = expression.getValue(); + if (value == null){ + continue; + } + builder.queryParam(expression.getName(), value); + } + MethodParameters parameters = MethodParameters.of(invocation.getMethod()); Iterator parameterValues = Arrays.asList(invocation.getArguments()).iterator(); diff --git a/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactoryUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactoryUnitTest.java index 1d930993..0b1a88b7 100644 --- a/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactoryUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactoryUnitTest.java @@ -50,6 +50,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Oliver Gierke * @author Kamill Sokol * @author Ross Turner + * @author Réda Housni Alaoui */ class WebMvcLinkBuilderFactoryUnitTest extends TestUtils { @@ -113,6 +114,13 @@ class WebMvcLinkBuilderFactoryUnitTest extends TestUtils { assertThat(link.getHref()).endsWith("/something/with%20blank/foo"); } + @Test + void linksToMethodWithPrimaryParam(){ + Link link = linkTo(methodOn(ControllerWithMethods.class).methodWithPrimaryParams()).withSelfRel(); + assertThat(link.getRel()).isEqualTo(IanaLinkRelations.SELF); + assertThat(link.getHref()).endsWith("/something/foo?a=1&b=2"); + } + /** * @see #96 */ diff --git a/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java b/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java index 6c2757ee..b13143b4 100644 --- a/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java @@ -58,6 +58,7 @@ import org.springframework.web.util.UriComponentsBuilder; * @author Kevin Conaway * @author Oliver Trosien * @author Greg Turnquist + * @author Réda Housni Alaoui */ class WebMvcLinkBuilderUnitTest extends TestUtils { @@ -666,6 +667,11 @@ class WebMvcLinkBuilderUnitTest extends TestUtils { return null; } + @RequestMapping(path = "/foo", params = {"a=1", "b=2", "c!=4", "!d"}) + HttpEntity methodWithPrimaryParams(){ + return null; + } + @RequestMapping(value = "/{id}/foo") HttpEntity methodForNextPage(@PathVariable String id, @RequestParam(required = false) Integer offset, @RequestParam Integer limit) {