reintroduced createBinder template method in Servlet/Portlet AnnotationMethodHandlerAdapter (SPR-6534)
This commit is contained in:
parent
2ce5090d00
commit
1e1964a060
|
|
@ -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.
|
||||
* <p>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 <code>null</code>
|
||||
* 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()) :
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
* <p>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 <code>null</code>
|
||||
* 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.
|
||||
*
|
||||
* <p>Uses the following algorithm: <ol> <li>If there is a type-level mapping with path information, it is {@linkplain
|
||||
* PathMatcher#combine(String, String) combined} with the method-level pattern. <li>If there is a {@linkplain
|
||||
* HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the request, it is combined with the
|
||||
|
|
@ -661,6 +682,26 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
|
|||
throw new HttpSessionRequiredException(message);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
|
||||
throws Exception {
|
||||
|
||||
return AnnotationMethodHandlerAdapter.this.createBinder(
|
||||
(HttpServletRequest) webRequest.getNativeRequest(), target, objectName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception {
|
||||
ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder;
|
||||
servletBinder.bind((ServletRequest) webRequest.getNativeRequest());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest();
|
||||
return new ServletServerHttpRequest(servletRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveDefaultValue(String value) {
|
||||
if (beanFactory == null) {
|
||||
|
|
@ -674,12 +715,6 @@ public class AnnotationMethodHandlerAdapter extends WebContentGenerator
|
|||
return exprResolver.evaluate(placeholdersResolved, expressionContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
HttpServletRequest servletRequest = (HttpServletRequest) webRequest.getNativeRequest();
|
||||
return new ServletServerHttpRequest(servletRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ import org.springframework.util.LinkedMultiValueMap;
|
|||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
|
|
@ -287,7 +288,7 @@ public class HandlerMethodInvoker {
|
|||
args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (attrName != null) {
|
||||
WebRequestDataBinder binder =
|
||||
WebDataBinder binder =
|
||||
resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
|
||||
boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
|
||||
if (binder.getTarget() != null) {
|
||||
|
|
@ -433,7 +434,7 @@ public class HandlerMethodInvoker {
|
|||
}
|
||||
paramValue = checkValue(paramName, paramValue, paramType);
|
||||
}
|
||||
WebRequestDataBinder binder = new WebRequestDataBinder(null, paramName);
|
||||
WebDataBinder binder = createBinder(webRequest, null, paramName);
|
||||
initBinder(handlerForInitBinderCall, paramName, binder, webRequest);
|
||||
return binder.convertIfNecessary(paramValue, paramType, methodParam);
|
||||
}
|
||||
|
|
@ -486,7 +487,7 @@ public class HandlerMethodInvoker {
|
|||
}
|
||||
headerValue = checkValue(headerName, headerValue, paramType);
|
||||
}
|
||||
WebRequestDataBinder binder = new WebRequestDataBinder(null, headerName);
|
||||
WebDataBinder binder = createBinder(webRequest, null, headerName);
|
||||
initBinder(handlerForInitBinderCall, headerName, binder, webRequest);
|
||||
return binder.convertIfNecessary(headerValue, paramType, methodParam);
|
||||
}
|
||||
|
|
@ -551,20 +552,9 @@ public class HandlerMethodInvoker {
|
|||
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}.
|
||||
* <p>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}.
|
||||
* <p>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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue