From 653f28727ca9cbdfdaaca646f8b5b8d93ddd86c5 Mon Sep 17 00:00:00 2001 From: Oliver Gierke Date: Thu, 2 Jan 2014 12:15:47 +0100 Subject: [PATCH] #122 - Fixed parameter binding for optional request parameters. If the method arguments handed into a dummy controller method invocation are required but null we now throw an exception as we cannot build a URI that hits the very same method in the very same way. Based on that, we now inspect @RequestParam annotated parameters for null values, allow them but don't bind a parameter for them anymore. --- .../AnnotatedParametersParameterAccessor.java | 31 +++++++++++++++- .../mvc/ControllerLinkBuilderFactory.java | 27 ++++++++++++-- .../mvc/ControllerLinkBuilderUnitTest.java | 36 +++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/springframework/hateoas/mvc/AnnotatedParametersParameterAccessor.java b/src/main/java/org/springframework/hateoas/mvc/AnnotatedParametersParameterAccessor.java index b00925c4..06b744db 100644 --- a/src/main/java/org/springframework/hateoas/mvc/AnnotatedParametersParameterAccessor.java +++ b/src/main/java/org/springframework/hateoas/mvc/AnnotatedParametersParameterAccessor.java @@ -65,12 +65,41 @@ class AnnotatedParametersParameterAccessor { List result = new ArrayList(); for (MethodParameter parameter : parameters.getParametersWith(attribute.getAnnotationType())) { - result.add(new BoundMethodParameter(parameter, arguments[parameter.getParameterIndex()], attribute)); + + Object value = arguments[parameter.getParameterIndex()]; + Object verifiedValue = verifyParameterValue(parameter, value); + + if (verifiedValue != null) { + result.add(new BoundMethodParameter(parameter, value, attribute)); + } } return result; } + /** + * Callback to verifiy the parameter values given for a dummy invocation. Default implementation rejects + * {@literal null} values as they indicate an invalid dummy call. + * + * @param parameter will never be {@literal null}. + * @param value could be {@literal null}. + * @return the verified value. + */ + protected Object verifyParameterValue(MethodParameter parameter, Object value) { + + if (value == null) { + + Object indexOrName = StringUtils.hasText(parameter.getParameterName()) ? parameter.getParameterName() : parameter + .getParameterIndex(); + + throw new IllegalArgumentException(String.format( + "Required controller parameter %s of method %s found but null value given!", indexOrName, + parameter.getMethod())); + } + + return value; + } + /** * Represents a {@link MethodParameter} alongside the value it has been bound to. * diff --git a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java index 882b4c68..8cc0d7e9 100644 --- a/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java +++ b/src/main/java/org/springframework/hateoas/mvc/ControllerLinkBuilderFactory.java @@ -56,8 +56,7 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory uriComponentsContributors = new ArrayList(); @@ -169,4 +168,28 @@ public class ControllerLinkBuilderFactory implements MethodLinkBuilderFactory methodWithRequestParam(@RequestParam String id) { + return null; + } + @RequestMapping(value = "/{id}/foo") HttpEntity methodForNextPage(@PathVariable String id, @RequestParam Integer offset, @RequestParam Integer limit) { @@ -334,5 +365,10 @@ public class ControllerLinkBuilderUnitTest extends TestUtils { @RequestParam Integer limit) { return null; } + + @RequestMapping(value = "/foo") + HttpEntity methodForOptionalNextPage(@RequestParam(required = false) Integer offset) { + return null; + } } }