#1653 - Tighten contracts for parameter values in MethodLinkBuilderFactory.linkTo(…).

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.
This commit is contained in:
Oliver Drotbohm
2021-09-24 16:19:18 +02:00
parent 5523dfbb2a
commit a43a3d68be
4 changed files with 33 additions and 11 deletions

View File

@@ -30,7 +30,8 @@ public interface MethodLinkBuilderFactory<T extends LinkBuilder> 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 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 +41,8 @@ public interface MethodLinkBuilderFactory<T extends LinkBuilder> 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. 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}.

View File

@@ -136,6 +136,12 @@ public class WebMvcLinkBuilder extends TemplateVariableAwareLinkBuilderSupport<W
Assert.notNull(method, "Method must not be null!");
Assert.notNull(parameters, "Parameters must not be null!");
int expected = method.getParameterTypes().length;
int given = parameters.length;
Assert.isTrue(expected == given,
() -> String.format("Incorrect number of parameter values given. Expected %s, got %s!", expected, given));
return linkTo(DummyInvocationUtils.getLastInvocationAware(controller, method, parameters));
}

View File

@@ -99,6 +99,15 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory<WebMvc
return WebMvcLinkBuilder.linkTo(controller, parameters);
}
/*
* (non-Javadoc)
* @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public WebMvcLinkBuilder linkTo(Method method, Object... parameters) {
return WebMvcLinkBuilder.linkTo(method, parameters);
}
/*
* (non-Javadoc)
* @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.Class, java.lang.reflect.Method, java.lang.Object[])
@@ -139,15 +148,6 @@ public class WebMvcLinkBuilderFactory implements MethodLinkBuilderFactory<WebMvc
}, builderFactory, getConversionService());
}
/*
* (non-Javadoc)
* @see org.springframework.hateoas.MethodLinkBuilderFactory#linkTo(java.lang.reflect.Method, java.lang.Object[])
*/
@Override
public WebMvcLinkBuilder linkTo(Method method, Object... parameters) {
return WebMvcLinkBuilder.linkTo(method, parameters);
}
private static Supplier<ConversionService> getConversionService() {
return () -> {

View File

@@ -26,6 +26,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.hateoas.IanaLinkRelations;
import org.springframework.hateoas.Link;
@@ -669,6 +670,19 @@ class WebMvcLinkBuilderUnitTest extends TestUtils {
assertThat(linkTo(method, new Object[] { null }).withSelfRel().getHref()).endsWith("?id={id}");
}
@Test // #1653
void buildsLinkWithoutParameterValuesGiven() throws Exception {
Method method = ControllerWithMethods.class.getDeclaredMethod("myMethod", Object.class);
Stream.<ThrowingCallable> of( //
() -> linkTo(method, new Object[0]), //
() -> linkTo(ControllerWithMethods.class, method, new Object[0]) //
) //
.map(assertThatIllegalArgumentException()::isThrownBy) //
.forEach(it -> it.withMessageContaining("Expected 1, got 0"));
}
private static UriComponents toComponents(Link link) {
return UriComponentsBuilder.fromUriString(link.expand().getHref()).build();
}