diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java index 5682353a8d..42b26dc293 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/RequestParamMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2018 the original author or authors. + * Copyright 2002-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.beans.PropertyEditor; import java.util.Collection; import java.util.List; import java.util.Map; +import java.util.Optional; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.Part; @@ -217,6 +218,11 @@ public class RequestParamMethodArgumentResolver extends AbstractNamedValueMethod parameter.getParameterName() : requestParam.name()); Assert.state(name != null, "Unresolvable parameter name"); + parameter = parameter.nestedIfOptional(); + if (value instanceof Optional) { + value = ((Optional) value).orElse(null); + } + if (value == null) { if (requestParam != null && (!requestParam.required() || !requestParam.defaultValue().equals(ValueConstants.DEFAULT_NONE))) { diff --git a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java index 2daac0d9ee..d36238cdbc 100644 --- a/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java +++ b/spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilderTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2012-2018 the original author or authors. + * Copyright 2012-2019 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.util.Arrays; import java.util.List; +import java.util.Optional; import javax.servlet.http.HttpServletRequest; import org.hamcrest.Matchers; @@ -264,6 +265,15 @@ public class MvcUriComponentsBuilderTests { assertThat(uriComponents.toUriString(), is("http://localhost/something/optional-param")); } + @Test // gh-22656 + public void fromMethodNameWithOptionalNamedParam() { + UriComponents uriComponents = fromMethodName(ControllerWithMethods.class, + "methodWithOptionalNamedParam", Optional.of("foo")).build(); + + assertThat(uriComponents.toUriString(), + is("http://localhost/something/optional-param-with-name?search=foo")); + } + @Test public void fromMethodNameWithMetaAnnotation() { UriComponents uriComponents = fromMethodName(MetaAnnotationController.class, "handleInput").build(); @@ -533,6 +543,11 @@ public class MvcUriComponentsBuilderTests { HttpEntity methodWithOptionalParam(@RequestParam(defaultValue = "") String q) { return null; } + + @GetMapping("/optional-param-with-name") + HttpEntity methodWithOptionalNamedParam(@RequestParam("search") Optional q) { + return null; + } }