From f0a000a07ed351e117b1482e9221f284a4891584 Mon Sep 17 00:00:00 2001 From: Oliver Drotbohm Date: Fri, 24 Sep 2021 16:19:18 +0200 Subject: [PATCH] =?UTF-8?q?#1652=20-=20Tighten=20contracts=20for=20paramet?= =?UTF-8?q?er=20values=20in=20MethodLinkBuilderFactory.linkTo(=E2=80=A6).?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If a parameter array is given to MethodLinkBuilderFactory.linkTo(…) methods, we now verify its correct length in correspondence to the method given. If no parameters are given at all, we automatically create a parameter value array of the required length. --- .../server/MethodLinkBuilderFactory.java | 27 ++++++++++++-- .../hateoas/server/mvc/WebMvcLinkBuilder.java | 27 ++++++++++++++ .../server/mvc/WebMvcLinkBuilderFactory.java | 36 ++++++++++++++----- .../server/mvc/WebMvcLinkBuilderUnitTest.java | 19 ++++++++++ 4 files changed, 98 insertions(+), 11 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/server/MethodLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/server/MethodLinkBuilderFactory.java index 863f26df..bd3a44d9 100644 --- a/src/main/java/org/springframework/hateoas/server/MethodLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/server/MethodLinkBuilderFactory.java @@ -30,7 +30,18 @@ public interface MethodLinkBuilderFactory extends LinkBui /** * Returns a {@link LinkBuilder} pointing to the URI mapped to the given {@link Method} and expanding this mapping - * using the given parameters. + * using {@literal null} values as parameters. + * + * @param method must not be {@literal null}. + * @return + * @since 1.4 + */ + T linkTo(Method method); + + /** + * Returns a {@link LinkBuilder} pointing to the URI mapped to the given {@link Method} and expanding this mapping + * using the given parameters. The number of parameter values has to match the length of the given method's expected + * parameters. * * @param method must not be {@literal null}. * @param parameters @@ -40,7 +51,19 @@ public interface MethodLinkBuilderFactory extends LinkBui /** * Returns a {@link LinkBuilder} pointing to the URI mapped to the given {@link Method} assuming it was invoked on an - * object of the given type. + * object of the given type expanding the mapping using {@literal null} values as parameters. + * + * @param type must not be {@literal null}. + * @param method must not be {@literal null}. + * @return + * @since 1.4 + */ + T linkTo(Class type, Method method); + + /** + * Returns a {@link LinkBuilder} pointing to the URI mapped to the given {@link Method} assuming it was invoked on an + * object of the given type. The number of parameter values has to match the length of the given method's expected + * parameters. * * @param type must not be {@literal null}. * @param method must not be {@literal null}. diff --git a/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilder.java b/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilder.java index 455d8e20..0c90a3b4 100644 --- a/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilder.java +++ b/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilder.java @@ -116,6 +116,16 @@ public class WebMvcLinkBuilder extends TemplateVariableAwareLinkBuilderSupport, Method) + */ + public static WebMvcLinkBuilder linkTo(Class controller, Method method) { + + Assert.notNull(controller, "Controller type must not be null!"); + Assert.notNull(method, "Method must not be null!"); + + return linkTo(controller, method, new Object[method.getParameterTypes().length]); + } + /* * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(Class, Method, Object...) */ @@ -136,6 +157,12 @@ public class WebMvcLinkBuilder extends TemplateVariableAwareLinkBuilderSupport String.format("Incorrect number of parameter values given. Expected %s, got %s!", expected, given)); + return linkTo(DummyInvocationUtils.getLastInvocationAware(controller, method, parameters)); } 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 10eef1f0..fdbfc983 100644 --- a/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderFactory.java @@ -103,6 +103,33 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory type, Method method) { + return WebMvcLinkBuilder.linkTo(type, method); + } + /* * (non-Javadoc) * @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Class, java.lang.reflect.Method, java.lang.Object[]) @@ -161,15 +188,6 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory getConversionService() { return () -> { 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 e2ea9965..77fa56de 100644 --- a/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java +++ b/src/test/java/org/springframework/hateoas/server/mvc/WebMvcLinkBuilderUnitTest.java @@ -30,6 +30,7 @@ import java.util.Map; import java.util.Optional; import java.util.stream.Stream; +import org.assertj.core.api.ThrowableAssert.ThrowingCallable; import org.junit.jupiter.api.Test; import org.springframework.core.convert.converter.Converter; import org.springframework.core.convert.support.ConfigurableConversionService; @@ -674,6 +675,24 @@ class WebMvcLinkBuilderUnitTest extends TestUtils { assertThat(result.getHref()).endsWith("?param=first"); } + @Test // #1652 + void buildsLinkWithoutParameterValuesGiven() throws Exception { + + Method method = ControllerWithMethods.class.getDeclaredMethod("myMethod", Object.class); + + Stream. of( // + () -> linkTo(method, new Object[0]), // + () -> linkTo(ControllerWithMethods.class, method, new Object[0]) // + ) // + .map(assertThatIllegalArgumentException()::isThrownBy) + .forEach(it -> it.withMessageContaining("Expected 1, got 0")); + + Stream. of( // + () -> linkTo(method), // + () -> linkTo(ControllerWithMethods.class, method) // + ).forEach(assertThatNoException()::isThrownBy); + } + private static UriComponents toComponents(Link link) { return UriComponentsBuilder.fromUriString(link.expand().getHref()).build(); }