diff --git a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java index 5ece3bbc877..7057743d4b2 100644 --- a/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ b/org.springframework.web.portlet/src/main/java/org/springframework/web/portlet/mvc/annotation/AnnotationMethodHandlerAdapter.java @@ -70,6 +70,7 @@ import org.springframework.util.ClassUtils; import org.springframework.util.ObjectUtils; import org.springframework.util.StringUtils; import org.springframework.validation.support.BindingAwareModelMap; +import org.springframework.web.bind.WebDataBinder; import org.springframework.web.bind.annotation.InitBinder; import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.RequestMapping; @@ -87,6 +88,7 @@ import org.springframework.web.context.request.RequestScope; import org.springframework.web.portlet.HandlerAdapter; import org.springframework.web.portlet.ModelAndView; import org.springframework.web.portlet.bind.MissingPortletRequestParameterException; +import org.springframework.web.portlet.bind.PortletRequestDataBinder; import org.springframework.web.portlet.bind.annotation.ActionMapping; import org.springframework.web.portlet.bind.annotation.EventMapping; import org.springframework.web.portlet.bind.annotation.RenderMapping; @@ -212,7 +214,7 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator } /** - * Set a custom WebArgumentResolvers to use for special method parameter types. + * Set a custom WebArgumentResolver to use for special method parameter types. * Such a custom WebArgumentResolver will kick in first, having a chance to * resolve an argument value before the standard argument handling kicks in. */ @@ -379,6 +381,26 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator } + /** + * Template method for creating a new PortletRequestDataBinder instance. + *
The default implementation creates a standard PortletRequestDataBinder.
+ * This can be overridden for custom PortletRequestDataBinder subclasses.
+ * @param request current portlet request
+ * @param target the target object to bind onto (or null
+ * if the binder is just used to convert a plain parameter value)
+ * @param objectName the objectName of the target object
+ * @return the PortletRequestDataBinder instance to use
+ * @throws Exception in case of invalid state or arguments
+ * @see PortletRequestDataBinder#bind(javax.portlet.PortletRequest)
+ * @see PortletRequestDataBinder#convertIfNecessary(Object, Class, MethodParameter)
+ */
+ protected PortletRequestDataBinder createBinder(
+ PortletRequest request, Object target, String objectName) throws Exception {
+
+ return new PortletRequestDataBinder(target, objectName);
+ }
+
+
/**
* Portlet-specific subclass of {@link HandlerMethodResolver}.
*/
@@ -507,6 +529,20 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator
throw new PortletSessionRequiredException(message);
}
+ @Override
+ protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
+ throws Exception {
+
+ return AnnotationMethodHandlerAdapter.this.createBinder(
+ (PortletRequest) webRequest.getNativeRequest(), target, objectName);
+ }
+
+ @Override
+ protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception {
+ PortletRequestDataBinder portletBinder = (PortletRequestDataBinder) binder;
+ portletBinder.bind((PortletRequest) webRequest.getNativeRequest());
+ }
+
@Override
protected Object resolveDefaultValue(String value) {
if (beanFactory == null) {
@@ -610,8 +646,8 @@ public class AnnotationMethodHandlerAdapter extends PortletContentGenerator
// Invoke custom resolvers if present...
if (customModelAndViewResolvers != null) {
for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) {
- org.springframework.web.servlet.ModelAndView smav = mavResolver
- .resolveModelAndView(handlerMethod, handlerType, returnValue, implicitModel, webRequest);
+ org.springframework.web.servlet.ModelAndView smav =
+ mavResolver.resolveModelAndView(handlerMethod, handlerType, returnValue, implicitModel, webRequest);
if (smav != ModelAndViewResolver.UNRESOLVED) {
return (smav.isReference() ?
new ModelAndView(smav.getViewName(), smav.getModelMap()) :
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 ef5e45fa9a8..fea02c54fbc 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
@@ -80,6 +80,8 @@ import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.HttpSessionRequiredException;
import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.ServletRequestDataBinder;
+import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
@@ -434,6 +436,26 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
}
+ /**
+ * Template method for creating a new ServletRequestDataBinder instance.
+ *
The default implementation creates a standard ServletRequestDataBinder.
+ * This can be overridden for custom ServletRequestDataBinder subclasses.
+ * @param request current HTTP request
+ * @param target the target object to bind onto (or null
+ * if the binder is just used to convert a plain parameter value)
+ * @param objectName the objectName of the target object
+ * @return the ServletRequestDataBinder instance to use
+ * @throws Exception in case of invalid state or arguments
+ * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest)
+ * @see ServletRequestDataBinder#convertIfNecessary(Object, Class, MethodParameter)
+ */
+ protected ServletRequestDataBinder createBinder(
+ HttpServletRequest request, Object target, String objectName) throws Exception {
+
+ return new ServletRequestDataBinder(target, objectName);
+ }
+
+
/**
* Servlet-specific subclass of {@link HandlerMethodResolver}.
*/
@@ -554,7 +576,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
/**
* Determines the matched pattern for the given methodLevelPattern and path.
- *
*
Uses the following algorithm:
Throws an UnsupportedOperationException by default. - */ - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); - } - - private Object resolveCookieValue(String cookieName, - boolean required, - String defaultValue, - MethodParameter methodParam, - NativeWebRequest webRequest, - Object handlerForInitBinderCall) throws Exception { + private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, + MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) + throws Exception { Class> paramType = methodParam.getParameterType(); if (cookieName.length() == 0) { @@ -580,7 +570,7 @@ public class HandlerMethodInvoker { } cookieValue = checkValue(cookieName, cookieValue, paramType); } - WebRequestDataBinder binder = new WebRequestDataBinder(null, cookieName); + WebDataBinder binder = createBinder(webRequest, null, cookieName); initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); return binder.convertIfNecessary(cookieValue, paramType, methodParam); } @@ -595,17 +585,15 @@ public class HandlerMethodInvoker { throw new UnsupportedOperationException("@CookieValue not supported"); } - private Object resolvePathVariable(String pathVarName, - MethodParameter methodParam, - NativeWebRequest webRequest, - Object handlerForInitBinderCall) throws Exception { + private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, + NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { Class> paramType = methodParam.getParameterType(); if (pathVarName.length() == 0) { pathVarName = getRequiredParameterName(methodParam); } String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); - WebRequestDataBinder binder = new WebRequestDataBinder(null, pathVarName); + WebDataBinder binder = createBinder(webRequest, null, pathVarName); initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); return binder.convertIfNecessary(pathVarValue, paramType, methodParam); } @@ -644,7 +632,7 @@ public class HandlerMethodInvoker { return value; } - private WebRequestDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, + private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { // Bind request parameter onto object... @@ -666,7 +654,7 @@ public class HandlerMethodInvoker { else { bindObject = BeanUtils.instantiateClass(paramType); } - WebRequestDataBinder binder = new WebRequestDataBinder(bindObject, name); + WebDataBinder binder = createBinder(webRequest, bindObject, name); initBinder(handler, name, binder, webRequest); return binder; } @@ -695,7 +683,7 @@ public class HandlerMethodInvoker { (isSessionAttr || isBindingCandidate(attrValue))) { String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; if (mavModel != null && !model.containsKey(bindingResultKey)) { - WebRequestDataBinder binder = new WebRequestDataBinder(attrValue, attrName); + WebDataBinder binder = createBinder(webRequest, attrValue, attrName); initBinder(handler, attrName, binder, webRequest); mavModel.put(bindingResultKey, binder.getBindingResult()); } @@ -740,18 +728,36 @@ public class HandlerMethodInvoker { throw new IllegalStateException(message); } - protected void doBind(WebRequestDataBinder binder, NativeWebRequest webRequest, boolean validate, - boolean failOnErrors) throws Exception { + protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) + throws Exception { - binder.bind(webRequest); + return new WebRequestDataBinder(target, objectName); + } + + private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) + throws Exception { + + doBind(binder, webRequest); if (validate) { binder.validate(); } - if (failOnErrors) { - binder.closeNoCatch(); + if (failOnErrors && binder.getBindingResult().hasErrors()) { + throw new BindException(binder.getBindingResult()); } } + protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { + ((WebRequestDataBinder) binder).bind(webRequest); + } + + /** + * 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"); + } + protected Object resolveDefaultValue(String value) { return value; }