request handler methods with @ModelAttribute annotation always return a model attribute (SPR-4867)

This commit is contained in:
Juergen Hoeller 2009-03-31 20:34:42 +00:00
parent 50f49ffca4
commit 72cc060eaf
3 changed files with 41 additions and 38 deletions

View File

@ -136,10 +136,10 @@ public class HandlerMethodInvoker {
Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args); Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args);
String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value(); String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value();
if ("".equals(attrName)) { if ("".equals(attrName)) {
Class resolvedType = Class resolvedType = GenericTypeResolver.resolveReturnType(
GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); attributeMethodToInvoke, handler.getClass());
attrName = attrName = Conventions.getVariableNameForReturnType(
Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); attributeMethodToInvoke, resolvedType, attrValue);
} }
implicitModel.addAttribute(attrName, attrValue); implicitModel.addAttribute(attrName, attrValue);
} }
@ -156,10 +156,8 @@ public class HandlerMethodInvoker {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private Object[] resolveHandlerArguments(Method handlerMethod, private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
Object handler, NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
NativeWebRequest webRequest,
ExtendedModelMap implicitModel) throws Exception {
Class[] paramTypes = handlerMethod.getParameterTypes(); Class[] paramTypes = handlerMethod.getParameterTypes();
Object[] args = new Object[paramTypes.length]; Object[] args = new Object[paramTypes.length];
@ -446,7 +444,6 @@ public class HandlerMethodInvoker {
throws Exception { throws Exception {
HttpInputMessage inputMessage = createHttpInputMessage(webRequest); HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
Class paramType = methodParam.getParameterType(); Class paramType = methodParam.getParameterType();
MediaType contentType = inputMessage.getHeaders().getContentType(); MediaType contentType = inputMessage.getHeaders().getContentType();
if (contentType == null) { if (contentType == null) {
@ -463,16 +460,14 @@ public class HandlerMethodInvoker {
} }
} }
} }
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
} }
/** /**
* Returns a {@link HttpInputMessage} for the given {@link NativeWebRequest}. * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}.
* Throws an UnsupportedOperationException by default. * Throws an UnsupportedOperationException by default.
*/ */
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
throw new UnsupportedOperationException("@RequestBody not supported"); throw new UnsupportedOperationException("@RequestBody not supported");
} }
@ -585,10 +580,8 @@ public class HandlerMethodInvoker {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final void updateModelAttributes(Object handler, public final void updateModelAttributes(Object handler, Map<String, Object> mavModel,
Map mavModel, ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception {
ExtendedModelMap implicitModel,
NativeWebRequest webRequest) throws Exception {
if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
@ -692,11 +685,22 @@ public class HandlerMethodInvoker {
} }
protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception {
if (WebRequest.class.isAssignableFrom(parameterType)) { if (WebRequest.class.isAssignableFrom(parameterType)) {
return webRequest; return webRequest;
} }
return WebArgumentResolver.UNRESOLVED; return WebArgumentResolver.UNRESOLVED;
} }
protected final void addReturnValueAsModelAttribute(
Method handlerMethod, Class handlerType, Object returnValue, ExtendedModelMap implicitModel) {
ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class);
String attrName = (attr != null ? attr.value() : "");
if ("".equals(attrName)) {
Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType);
attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue);
}
implicitModel.addAttribute(attrName, returnValue);
}
} }

View File

@ -45,8 +45,6 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeanUtils; import org.springframework.beans.BeanUtils;
import org.springframework.core.Conventions;
import org.springframework.core.GenericTypeResolver;
import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
import org.springframework.core.MethodParameter; import org.springframework.core.MethodParameter;
import org.springframework.core.ParameterNameDiscoverer; import org.springframework.core.ParameterNameDiscoverer;
@ -662,12 +660,16 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
else if (returnValue instanceof Model) { else if (returnValue instanceof Model) {
return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap());
} }
else if (returnValue instanceof Map) {
return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue);
}
else if (returnValue instanceof View) { else if (returnValue instanceof View) {
return new ModelAndView((View) returnValue).addAllObjects(implicitModel); return new ModelAndView((View) returnValue).addAllObjects(implicitModel);
} }
else if (handlerMethod.isAnnotationPresent(ModelAttribute.class)) {
addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
return new ModelAndView().addAllObjects(implicitModel);
}
else if (returnValue instanceof Map) {
return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue);
}
else if (returnValue instanceof String) { else if (returnValue instanceof String) {
return new ModelAndView((String) returnValue).addAllObjects(implicitModel); return new ModelAndView((String) returnValue).addAllObjects(implicitModel);
} }
@ -683,14 +685,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
} }
else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) {
// Assume a single model attribute... // Assume a single model attribute...
ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel);
String attrName = (attr != null ? attr.value() : ""); return new ModelAndView().addAllObjects(implicitModel);
ModelAndView mav = new ModelAndView().addAllObjects(implicitModel);
if ("".equals(attrName)) {
Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType);
attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue);
}
return mav.addObject(attrName, returnValue);
} }
else { else {
throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); throw new IllegalArgumentException("Invalid handler method return value: " + returnValue);
@ -726,6 +722,7 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen
} }
} }
/** /**
* Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will
* result in: <ul> <li>RHIs with {@linkplain RequestMappingInfo#matchedPaths better matched paths} take prescedence * result in: <ul> <li>RHIs with {@linkplain RequestMappingInfo#matchedPaths better matched paths} take prescedence

View File

@ -346,7 +346,7 @@ public class ServletAnnotationControllerTests {
request.addParameter("age", "value2"); request.addParameter("age", "value2");
MockHttpServletResponse response = new MockHttpServletResponse(); MockHttpServletResponse response = new MockHttpServletResponse();
servlet.service(request, response); servlet.service(request, response);
assertEquals("myView-name1-typeMismatch-tb1-myValue", response.getContentAsString()); assertEquals("myPath-name1-typeMismatch-tb1-myValue-yourValue", response.getContentAsString());
} }
@Test @Test
@ -360,8 +360,7 @@ public class ServletAnnotationControllerTests {
DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator(); DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
autoProxyCreator.setBeanFactory(wac.getBeanFactory()); autoProxyCreator.setBeanFactory(wac.getBeanFactory());
wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator); wac.getBeanFactory().addBeanPostProcessor(autoProxyCreator);
wac.getBeanFactory() wac.getBeanFactory().registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
.registerSingleton("advisor", new DefaultPointcutAdvisor(new SimpleTraceInterceptor()));
wac.refresh(); wac.refresh();
return wac; return wac;
} }
@ -1108,11 +1107,12 @@ public class ServletAnnotationControllerTests {
} }
@RequestMapping("/myPath.do") @RequestMapping("/myPath.do")
@ModelAttribute("yourKey")
public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, Model model) { public String myHandle(@ModelAttribute("myCommand") TestBean tb, BindingResult errors, Model model) {
if (!model.containsAttribute("myKey")) { if (!model.containsAttribute("myKey")) {
model.addAttribute("myKey", "myValue"); model.addAttribute("myKey", "myValue");
} }
return "myView"; return "yourValue";
} }
} }
@ -1379,9 +1379,9 @@ public class ServletAnnotationControllerTests {
} }
List<TestBean> testBeans = (List<TestBean>) model.get("testBeanList"); List<TestBean> testBeans = (List<TestBean>) model.get("testBeanList");
if (errors.hasFieldErrors("age")) { if (errors.hasFieldErrors("age")) {
response.getWriter() response.getWriter().write(viewName + "-" + tb.getName() + "-" +
.write(viewName + "-" + tb.getName() + "-" + errors.getFieldError("age").getCode() + errors.getFieldError("age").getCode() + "-" + testBeans.get(0).getName() + "-" +
"-" + testBeans.get(0).getName() + "-" + model.get("myKey")); model.get("myKey") + (model.containsKey("yourKey") ? "-" + model.get("yourKey") : ""));
} }
else { else {
response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" + response.getWriter().write(viewName + "-" + tb.getName() + "-" + tb.getAge() + "-" +
@ -1472,6 +1472,7 @@ public class ServletAnnotationControllerTests {
} }
} }
@Controller @Controller
public static class PathOrderingController { public static class PathOrderingController {
@ -1486,6 +1487,7 @@ public class ServletAnnotationControllerTests {
} }
} }
@Controller @Controller
public static class RequestBodyController { public static class RequestBodyController {
@ -1495,6 +1497,7 @@ public class ServletAnnotationControllerTests {
} }
} }
public static class MyMessageConverter implements HttpMessageConverter { public static class MyMessageConverter implements HttpMessageConverter {
public boolean supports(Class clazz) { public boolean supports(Class clazz) {
@ -1516,5 +1519,4 @@ public class ServletAnnotationControllerTests {
} }
} }
} }