ModelAttributeMethodProcessor detects re-enabled binding declaration

Issue: SPR-16083

(cherry picked from commit bec1fc1)
This commit is contained in:
Juergen Hoeller
2017-10-18 12:31:22 +02:00
parent d473506d32
commit b0ae8f6058
5 changed files with 123 additions and 71 deletions

View File

@@ -43,6 +43,7 @@ import org.springframework.web.servlet.HandlerMapping;
* model attribute name and there is an appropriate type conversion strategy.
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
* @since 3.1
*/
public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodProcessor {
@@ -66,19 +67,19 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
* @see #createAttributeFromRequestValue
*/
@Override
protected final Object createAttribute(String attributeName, MethodParameter methodParam,
protected final Object createAttribute(String attributeName, MethodParameter parameter,
WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception {
String value = getRequestValueForAttribute(attributeName, request);
if (value != null) {
Object attribute = createAttributeFromRequestValue(
value, attributeName, methodParam, binderFactory, request);
value, attributeName, parameter, binderFactory, request);
if (attribute != null) {
return attribute;
}
}
return super.createAttribute(attributeName, methodParam, binderFactory, request);
return super.createAttribute(attributeName, parameter, binderFactory, request);
}
/**
@@ -117,24 +118,23 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr
* {@link Converter} that can perform the conversion.
* @param sourceValue the source value to create the model attribute from
* @param attributeName the name of the attribute (never {@code null})
* @param methodParam the method parameter
* @param parameter the method parameter
* @param binderFactory for creating WebDataBinder instance
* @param request the current request
* @return the created model attribute, or {@code null} if no suitable
* conversion found
* @throws Exception
*/
protected Object createAttributeFromRequestValue(String sourceValue, String attributeName,
MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request)
MethodParameter parameter, WebDataBinderFactory binderFactory, NativeWebRequest request)
throws Exception {
DataBinder binder = binderFactory.createBinder(request, null, attributeName);
ConversionService conversionService = binder.getConversionService();
if (conversionService != null) {
TypeDescriptor source = TypeDescriptor.valueOf(String.class);
TypeDescriptor target = new TypeDescriptor(methodParam);
TypeDescriptor target = new TypeDescriptor(parameter);
if (conversionService.canConvert(source, target)) {
return binder.convertIfNecessary(sourceValue, methodParam.getParameterType(), methodParam);
return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter);
}
}
return null;

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@@ -159,6 +159,7 @@ import static org.junit.Assert.*;
* </ul>
*
* @author Rossen Stoyanchev
* @author Juergen Hoeller
*/
public class ServletAnnotationControllerHandlerMethodTests extends AbstractServletHandlerMethodTests {
@@ -580,6 +581,20 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
assertEquals("myPath-name1-typeMismatch-tb1-myValue-yourValue", response.getContentAsString());
}
@Test
public void lateBindingFormController() throws Exception {
initServlet(
wac -> wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)),
LateBindingFormController.class);
MockHttpServletRequest request = new MockHttpServletRequest("GET", "/myPath.do");
request.addParameter("name", "name1");
request.addParameter("age", "value2");
MockHttpServletResponse response = new MockHttpServletResponse();
getServlet().service(request, response);
assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString());
}
@Test
public void proxiedFormController() throws Exception {
initServlet(new ApplicationContextInitializer<GenericWebApplicationContext>() {
@@ -2157,6 +2172,29 @@ public class ServletAnnotationControllerHandlerMethodTests extends AbstractServl
}
}
@Controller
public static class LateBindingFormController {
@ModelAttribute("testBeanList")
public List<TestBean> getTestBeans(@ModelAttribute(name="myCommand", binding=false) TestBean tb) {
List<TestBean> list = new LinkedList<>();
list.add(new TestBean("tb1"));
list.add(new TestBean("tb2"));
return list;
}
@RequestMapping("/myPath.do")
public String myHandle(@ModelAttribute(name="myCommand", binding=true) TestBean tb, BindingResult errors, ModelMap model) {
FieldError error = errors.getFieldError("age");
assertNotNull("Must have field error for age property", error);
assertEquals("value2", error.getRejectedValue());
if (!model.containsKey("myKey")) {
model.addAttribute("myKey", "myValue");
}
return "myView";
}
}
@Controller
static class MyCommandProvidingFormController<T, TB, TB2> extends MyFormController {