From 72cc060eafe1629ace086701bd9f58237de8439d Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Tue, 31 Mar 2009 20:34:42 +0000 Subject: [PATCH] request handler methods with @ModelAttribute annotation always return a model attribute (SPR-4867) --- .../support/HandlerMethodInvoker.java | 38 ++++++++++--------- .../AnnotationMethodHandlerAdapter.java | 23 +++++------ .../ServletAnnotationControllerTests.java | 18 +++++---- 3 files changed, 41 insertions(+), 38 deletions(-) diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java index 9ba572d88fe..c403f6bd4da 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/bind/annotation/support/HandlerMethodInvoker.java @@ -136,10 +136,10 @@ public class HandlerMethodInvoker { Object attrValue = doInvokeMethod(attributeMethodToInvoke, handler, args); String attrName = AnnotationUtils.findAnnotation(attributeMethodToInvoke, ModelAttribute.class).value(); if ("".equals(attrName)) { - Class resolvedType = - GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = - Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); + Class resolvedType = GenericTypeResolver.resolveReturnType( + attributeMethodToInvoke, handler.getClass()); + attrName = Conventions.getVariableNameForReturnType( + attributeMethodToInvoke, resolvedType, attrValue); } implicitModel.addAttribute(attrName, attrValue); } @@ -156,10 +156,8 @@ public class HandlerMethodInvoker { } @SuppressWarnings("unchecked") - private Object[] resolveHandlerArguments(Method handlerMethod, - Object handler, - NativeWebRequest webRequest, - ExtendedModelMap implicitModel) throws Exception { + private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, + NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { Class[] paramTypes = handlerMethod.getParameterTypes(); Object[] args = new Object[paramTypes.length]; @@ -446,7 +444,6 @@ public class HandlerMethodInvoker { throws Exception { HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - Class paramType = methodParam.getParameterType(); MediaType contentType = inputMessage.getHeaders().getContentType(); if (contentType == null) { @@ -463,16 +460,14 @@ public class HandlerMethodInvoker { } } } - 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. */ protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); } @@ -585,10 +580,8 @@ public class HandlerMethodInvoker { } @SuppressWarnings("unchecked") - public final void updateModelAttributes(Object handler, - Map mavModel, - ExtendedModelMap implicitModel, - NativeWebRequest webRequest) throws Exception { + public final void updateModelAttributes(Object handler, Map mavModel, + ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { @@ -692,11 +685,22 @@ public class HandlerMethodInvoker { } protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - if (WebRequest.class.isAssignableFrom(parameterType)) { return webRequest; } 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); + } + } diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 4cc68680ce3..0f4bda10e09 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -45,8 +45,6 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.beans.BeanUtils; -import org.springframework.core.Conventions; -import org.springframework.core.GenericTypeResolver; import org.springframework.core.LocalVariableTableParameterNameDiscoverer; import org.springframework.core.MethodParameter; import org.springframework.core.ParameterNameDiscoverer; @@ -662,12 +660,16 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen else if (returnValue instanceof Model) { 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) { 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) { return new ModelAndView((String) returnValue).addAllObjects(implicitModel); } @@ -683,14 +685,8 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator implemen } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { // Assume a single model attribute... - ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); - String attrName = (attr != null ? attr.value() : ""); - 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); + addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); + return new ModelAndView().addAllObjects(implicitModel); } else { 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 * result in: