Revised handling of missing data class arguments

Includes unified detection of Kotlin's optional parameters in MethodParameter.isOptional(), reduces BeanUtils.findPrimaryConstructor to Kotlin semantics (for reuse in AutowiredAnnotationBeanPostProcessor), and finally introduces a common KotlinDetector delegate with an isKotlinType(Class) check.

Issue: SPR-15877
Issue: SPR-16020
This commit is contained in:
Juergen Hoeller
2017-09-28 00:31:12 +02:00
parent d3129a8bd7
commit ec345bf162
14 changed files with 204 additions and 344 deletions

View File

@@ -69,6 +69,7 @@ import org.springframework.beans.propertyeditors.CustomDateEditor;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.core.MethodParameter;
import org.springframework.core.convert.converter.Converter;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionServiceFactoryBean;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -99,6 +100,7 @@ import org.springframework.tests.sample.beans.TestBean;
import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.util.Assert;
import org.springframework.util.MultiValueMap;
import org.springframework.util.SerializationTestUtils;
import org.springframework.util.StringUtils;
@@ -1761,6 +1763,30 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals("value1-true-3", response.getContentAsString());
}
@Test
public void dataClassBindingWithOptionalParameter() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param1", "value1");
request.addParameter("param2", "true");
request.addParameter("optionalParam", "8");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals("value1-true-8", response.getContentAsString());
}
@Test
public void dataClassBindingWithMissingParameter() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/bind");
request.addParameter("param1", "value1");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertTrue(response.getContentAsString().contains("field 'param2'"));
}
@Test
public void dataClassBindingWithConversionError() throws Exception {
initServletWithControllers(ValidatedDataClassController.class);
@@ -3390,10 +3416,12 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
public int param3;
@ConstructorProperties({"param1", "param2"})
public DataClass(String param1, boolean p2) {
@ConstructorProperties({"param1", "param2", "optionalParam"})
public DataClass(String param1, boolean p2, Optional<Integer> optionalParam) {
this.param1 = param1;
this.param2 = p2;
Assert.notNull(optionalParam, "Optional must not be null");
optionalParam.ifPresent(integer -> this.param3 = integer);
}
public void setParam3(int param3) {
@@ -3418,6 +3446,7 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
LocalValidatorFactoryBean vf = new LocalValidatorFactoryBean();
vf.afterPropertiesSet();
binder.setValidator(vf);
binder.setConversionService(new DefaultFormattingConversionService());
}
@RequestMapping("/bind")