POLISH ARGUMENT RESOLVERS AND RETURN VALUE HANDLERS.
This commit is contained in:
@@ -20,7 +20,8 @@ import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
* Creates a {@link WebRequestDataBinder} and initializes it through a {@link WebBindingInitializer}.
|
||||
* Create a {@link WebRequestDataBinder} instance and initialize it with a
|
||||
* {@link WebBindingInitializer}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -30,34 +31,31 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
|
||||
private final WebBindingInitializer initializer;
|
||||
|
||||
/**
|
||||
* Create {@link DefaultDataBinderFactory} instance.
|
||||
* @param initializer a global initializer to initialize new data binder instances with
|
||||
* Create new instance.
|
||||
* @param initializer for global data binder intialization, or {@code null}
|
||||
*/
|
||||
public DefaultDataBinderFactory(WebBindingInitializer initializer) {
|
||||
this.initializer = initializer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new {@link WebDataBinder} for the given target object and initialize it through
|
||||
* a {@link WebBindingInitializer}.
|
||||
* Create a new {@link WebDataBinder} for the given target object and
|
||||
* initialize it through a {@link WebBindingInitializer}.
|
||||
*/
|
||||
public final WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) throws Exception {
|
||||
WebDataBinder dataBinder = createBinderInstance(target, objectName, webRequest);
|
||||
|
||||
if (initializer != null) {
|
||||
this.initializer.initBinder(dataBinder, webRequest);
|
||||
}
|
||||
|
||||
initBinder(dataBinder, webRequest);
|
||||
|
||||
return dataBinder;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension hook that subclasses can use to create a data binder of a specific type.
|
||||
* The default implementation creates a {@link WebRequestDataBinder}.
|
||||
* @param target the data binding target object; or {@code null} for type conversion on simple objects.
|
||||
* @param objectName the name of the target object
|
||||
* Extension point to create the WebDataBinder instance, which is
|
||||
* {@link WebRequestDataBinder} by default.
|
||||
* @param target the binding target or {@code null} for type conversion only
|
||||
* @param objectName the binding target object name
|
||||
* @param webRequest the current request
|
||||
*/
|
||||
protected WebDataBinder createBinderInstance(Object target, String objectName, NativeWebRequest webRequest) {
|
||||
@@ -65,8 +63,9 @@ public class DefaultDataBinderFactory implements WebDataBinderFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension hook that subclasses can override to initialize further the data binder.
|
||||
* Will be invoked after the data binder is initialized through the {@link WebBindingInitializer}.
|
||||
* Extension point to further initialize the created data binder instance
|
||||
* (e.g. with {@code @InitBinder} methods) after "global" initializaton
|
||||
* via {@link WebBindingInitializer}.
|
||||
* @param dataBinder the data binder instance to customize
|
||||
* @param webRequest the current request
|
||||
* @throws Exception if initialization fails
|
||||
|
||||
@@ -30,7 +30,7 @@ import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.method.support.InvocableHandlerMethod;
|
||||
|
||||
/**
|
||||
* Adds data binder initialization through the invocation of @{@link InitBinder} methods.
|
||||
* Adds initialization to a WebDataBinder via {@code @InitBinder} methods.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -41,8 +41,8 @@ public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
|
||||
|
||||
/**
|
||||
* Create a new instance.
|
||||
* @param binderMethods {@link InitBinder} methods to initialize new data binder instances with
|
||||
* @param initializer a global initializer to initialize new data binder instances with
|
||||
* @param binderMethods {@code @InitBinder} methods, or {@code null}
|
||||
* @param initializer for global data binder intialization
|
||||
*/
|
||||
public InitBinderDataBinderFactory(List<InvocableHandlerMethod> binderMethods, WebBindingInitializer initializer) {
|
||||
super(initializer);
|
||||
@@ -50,16 +50,15 @@ public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the given data binder through the invocation of @{@link InitBinder} methods.
|
||||
* An @{@link InitBinder} method that defines names via {@link InitBinder#value()} will
|
||||
* not be invoked unless one of the names matches the target object name.
|
||||
* @see InitBinder#value()
|
||||
* Initialize a WebDataBinder with {@code @InitBinder} methods.
|
||||
* If the {@code @InitBinder} annotation specifies attributes names, it is
|
||||
* invoked only if the names include the target object name.
|
||||
* @throws Exception if one of the invoked @{@link InitBinder} methods fail.
|
||||
*/
|
||||
@Override
|
||||
public void initBinder(WebDataBinder binder, NativeWebRequest request) throws Exception {
|
||||
for (InvocableHandlerMethod binderMethod : this.binderMethods) {
|
||||
if (!isBinderMethodApplicable(binderMethod, binder)) {
|
||||
if (!invokeInitBinderMethod(binderMethod, binder)) {
|
||||
continue;
|
||||
}
|
||||
Object returnValue = binderMethod.invokeForRequest(request, null, binder);
|
||||
@@ -70,12 +69,12 @@ public class InitBinderDataBinderFactory extends DefaultDataBinderFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the given @{@link InitBinder} method should be invoked to initialize
|
||||
* the given {@link WebDataBinder} instance. This implementations returns {@code true} if
|
||||
* the @{@link InitBinder} annotation on the method does not define any names or if one of the
|
||||
* names it defines names matches the target object name.
|
||||
* Return {@code true} if the given {@code @InitBinder} method should be
|
||||
* invoked to initialize the given WebDataBinder.
|
||||
* <p>The default implementation checks if target object name is included
|
||||
* in the attribute names specified in the {@code @InitBinder} annotation.
|
||||
*/
|
||||
protected boolean isBinderMethodApplicable(HandlerMethod binderMethod, WebDataBinder binder) {
|
||||
protected boolean invokeInitBinderMethod(HandlerMethod binderMethod, WebDataBinder binder) {
|
||||
InitBinder annot = binderMethod.getMethodAnnotation(InitBinder.class);
|
||||
Collection<String> names = Arrays.asList(annot.value());
|
||||
return (names.size() == 0 || names.contains(binder.getObjectName()));
|
||||
|
||||
@@ -23,15 +23,15 @@ import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
|
||||
/**
|
||||
* A base abstract class to resolve method arguments annotated with @{@link CookieValue}. Subclasses must define how
|
||||
* to extract the cookie value from the request.
|
||||
* A base abstract class to resolve method arguments annotated with
|
||||
* {@code @CookieValue}. Subclasses extract the cookie value from the request.
|
||||
*
|
||||
* <p>An @{@link CookieValue} is a named value that is resolved from a cookie. It has a required flag and a
|
||||
* default value to fall back on when the cookie does not exist. See the base class
|
||||
* {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed.
|
||||
* <p>An {@code @CookieValue} is a named value that is resolved from a cookie.
|
||||
* It has a required flag and a default value to fall back on when the cookie
|
||||
* does not exist.
|
||||
*
|
||||
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved cookie values that don't yet match
|
||||
* the method parameter type.
|
||||
* <p>A {@link WebDataBinder} may be invoked to apply type conversion to the
|
||||
* resolved cookie value.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -40,8 +40,9 @@ import org.springframework.web.bind.annotation.CookieValue;
|
||||
public abstract class AbstractCookieValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
|
||||
|
||||
/**
|
||||
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
|
||||
* in default values, or {@code null} if default values are not expected to contain expressions
|
||||
* @param beanFactory a bean factory to use for resolving ${...}
|
||||
* placeholder and #{...} SpEL expressions in default values;
|
||||
* or {@code null} if default values are not expected to contain expressions
|
||||
*/
|
||||
public AbstractCookieValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
|
||||
@@ -21,7 +21,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.support.WebArgumentResolver;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -29,18 +28,18 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* An abstract base class adapting a {@link WebArgumentResolver} into the {@link HandlerMethodArgumentResolver}
|
||||
* contract. Provided for backwards compatibility, some important considerations are listed below.
|
||||
*
|
||||
* <p>The method {@link #supportsParameter(MethodParameter)} is implemented by trying to resolve the value through
|
||||
* the {@link WebArgumentResolver} and verifying the resulting value is not {@link WebArgumentResolver#UNRESOLVED}.
|
||||
* Exceptions resulting from that are absorbed and ignored since the adapter can't be sure if this is the resolver
|
||||
* that supports the method parameter or not. To avoid this limitation change the {@link WebArgumentResolver} to
|
||||
* implement the {@link HandlerMethodArgumentResolver} contract instead.
|
||||
* An abstract base class adapting a {@link WebArgumentResolver} to the
|
||||
* {@link HandlerMethodArgumentResolver} contract.
|
||||
*
|
||||
* <p>Another potentially useful advantage of {@link HandlerMethodArgumentResolver} is that it provides access to
|
||||
* model attributes through the {@link ModelAndViewContainer} as well as access to a {@link WebDataBinderFactory}
|
||||
* for when type conversion through a {@link WebDataBinder} is needed.
|
||||
* <p><strong>Note:</strong> This class is provided for backwards compatibility.
|
||||
* However it is recommended to re-write a {@code WebArgumentResolver} as
|
||||
* {@code HandlerMethodArgumentResolver}. Since {@link #supportsParameter}
|
||||
* can only be implemented by actually resolving the value and then checking
|
||||
* the result is not {@code WebArgumentResolver#UNRESOLVED} any exceptions
|
||||
* raised must be absorbed and ignored since it's not clear whether the adapter
|
||||
* doesn't support the parameter or whether it failed for an internal reason.
|
||||
* The {@code HandlerMethodArgumentResolver} contract also provides access to
|
||||
* model attributes and to {@code WebDataBinderFactory} (for type conversion).
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -53,7 +52,7 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
|
||||
private final WebArgumentResolver adaptee;
|
||||
|
||||
/**
|
||||
* Create a {@link AbstractWebArgumentResolverAdapter} with the {@link WebArgumentResolver} instance to delegate to.
|
||||
* Create a new instance.
|
||||
*/
|
||||
public AbstractWebArgumentResolverAdapter(WebArgumentResolver adaptee) {
|
||||
Assert.notNull(adaptee, "'adaptee' must not be null");
|
||||
@@ -61,12 +60,13 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
|
||||
}
|
||||
|
||||
/**
|
||||
* See the class-level documentation for an important consideration about exceptions arising in this method.
|
||||
* Actually resolve the value and check the resolved value is not
|
||||
* {@link WebArgumentResolver#UNRESOLVED} absorbing _any_ exceptions.
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
try {
|
||||
NativeWebRequest webRequest = getWebRequest();
|
||||
Object result = adaptee.resolveArgument(parameter, webRequest);
|
||||
Object result = this.adaptee.resolveArgument(parameter, webRequest);
|
||||
if (result == WebArgumentResolver.UNRESOLVED) {
|
||||
return false;
|
||||
}
|
||||
@@ -82,21 +82,21 @@ public abstract class AbstractWebArgumentResolverAdapter implements HandlerMetho
|
||||
}
|
||||
|
||||
/**
|
||||
* Provide access to a {@link NativeWebRequest}.
|
||||
* Required for access to NativeWebRequest in {@link #supportsParameter}.
|
||||
*/
|
||||
protected abstract NativeWebRequest getWebRequest();
|
||||
|
||||
/**
|
||||
* Resolves the argument value by delegating to the {@link WebArgumentResolver} instance.
|
||||
* @exception IllegalStateException if the resolved value is {@link WebArgumentResolver#UNRESOLVED} or if the
|
||||
* return value type cannot be assigned to the method parameter type.
|
||||
* Delegate to the {@link WebArgumentResolver} instance.
|
||||
* @exception IllegalStateException if the resolved value is not assignable
|
||||
* to the method parameter.
|
||||
*/
|
||||
public Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
NativeWebRequest webRequest,
|
||||
WebDataBinderFactory binderFactory) throws Exception {
|
||||
Class<?> paramType = parameter.getParameterType();
|
||||
Object result = adaptee.resolveArgument(parameter, webRequest);
|
||||
Object result = this.adaptee.resolveArgument(parameter, webRequest);
|
||||
if (result == WebArgumentResolver.UNRESOLVED || !ClassUtils.isAssignableValue(paramType, result)) {
|
||||
throw new IllegalStateException(
|
||||
"Standard argument type [" + paramType.getName() + "] in method " + parameter.getMethod() +
|
||||
|
||||
@@ -28,10 +28,12 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves method arguments of type {@link Errors} and {@link BindingResult}.
|
||||
* Resolves {@link Errors} method arguments.
|
||||
*
|
||||
* <p>This argument should appear after a model attribute argument in the signature of the handler method.
|
||||
* It is resolved by accessing the last attribute in the model expecting that to be a {@link BindingResult}.
|
||||
* <p>An {@code Errors} method argument is expected to appear immediately after
|
||||
* the model attribute in the method signature. It is resolved by expecting the
|
||||
* last two attributes added to the model to be the model attribute and its
|
||||
* {@link BindingResult}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -57,8 +59,8 @@ public class ErrorsMethodArgumentResolver implements HandlerMethodArgumentResolv
|
||||
}
|
||||
|
||||
throw new IllegalStateException(
|
||||
"An Errors/BindingResult argument must follow a model attribute argument. " +
|
||||
"Check your handler method signature: " + parameter.getMethod());
|
||||
"An Errors/BindingResult argument is expected to be immediately after the model attribute " +
|
||||
"argument in the controller method signature: " + parameter.getMethod());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,14 +25,14 @@ import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with @{@link Value}.
|
||||
* Resolves method arguments annotated with {@code @Value}.
|
||||
*
|
||||
* <p>An @{@link Value} is a named value that does not have a name but gets resolved from a default value string
|
||||
* that may contain ${...} placeholder or Spring Expression Language #{...} expressions. See the base class
|
||||
* {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed.
|
||||
* <p>An {@code @Value} does not have a name but gets resolved from the default
|
||||
* value string, which may contain ${...} placeholder or Spring Expression
|
||||
* Language #{...} expressions.
|
||||
*
|
||||
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved argument values that don't yet match
|
||||
* the method parameter type.
|
||||
* <p>A {@link WebDataBinder} may be invoked to apply type conversion to
|
||||
* resolved argument value.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -40,8 +40,9 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
public class ExpressionValueMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
|
||||
|
||||
/**
|
||||
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
|
||||
* in default values, or {@code null} if default values are not expected to contain expressions
|
||||
* @param beanFactory a bean factory to use for resolving ${...}
|
||||
* placeholder and #{...} SpEL expressions in default values;
|
||||
* or {@code null} if default values are not expected to contain expressions
|
||||
*/
|
||||
public ExpressionValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
|
||||
@@ -23,7 +23,6 @@ import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
@@ -36,15 +35,18 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with @{@link ModelAttribute}. Or if created in default resolution mode,
|
||||
* resolves any non-simple type argument even without an @{@link ModelAttribute}. See the constructor for details.
|
||||
* Resolves method arguments annotated with {@code @ModelAttribute} and handles
|
||||
* return values from methods annotated with {@code @ModelAttribute}.
|
||||
*
|
||||
* <p>Model attributes are obtained from the model or if not found possibly
|
||||
* created with a default constructor if it is available. Once created, the
|
||||
* attributed is populated with request data via data binding and also
|
||||
* validation may be applied if the argument is annotated with
|
||||
* {@code @javax.validation.Valid}.
|
||||
*
|
||||
* <p>A model attribute argument is obtained from the model or otherwise is created with a default constructor.
|
||||
* Data binding and validation are applied through a {@link WebDataBinder} instance. Validation is applied
|
||||
* only when the argument is also annotated with {@code @Valid}.
|
||||
*
|
||||
* <p>Also handles return values from methods annotated with an @{@link ModelAttribute}. The return value is
|
||||
* added to the {@link ModelAndViewContainer}.
|
||||
* <p>When this handler is created with {@code annotationNotRequired=true},
|
||||
* any non-simple type argument and return value is regarded as a model
|
||||
* attribute with or without the presence of an {@code @ModelAttribute}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -53,26 +55,27 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
|
||||
protected Log logger = LogFactory.getLog(this.getClass());
|
||||
|
||||
private final boolean useDefaultResolution;
|
||||
private final boolean annotationNotRequired;
|
||||
|
||||
/**
|
||||
* @param useDefaultResolution in default resolution mode a method argument that isn't a simple type, as
|
||||
* defined in {@link BeanUtils#isSimpleProperty(Class)}, is treated as a model attribute even if it doesn't
|
||||
* have an @{@link ModelAttribute} annotation with its name derived from the model attribute type.
|
||||
* @param annotationNotRequired if {@code true}, any non-simple type
|
||||
* argument or return value is regarded as a model attribute even without
|
||||
* the presence of a {@code @ModelAttribute} annotation in which case the
|
||||
* attribute name is derived from the model attribute's type.
|
||||
*/
|
||||
public ModelAttributeMethodProcessor(boolean useDefaultResolution) {
|
||||
this.useDefaultResolution = useDefaultResolution;
|
||||
public ModelAttributeMethodProcessor(boolean annotationNotRequired) {
|
||||
this.annotationNotRequired = annotationNotRequired;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the parameter is annotated with {@link ModelAttribute} or if it is a
|
||||
* simple type without any annotations.
|
||||
* @return true if the parameter is annotated with {@link ModelAttribute}
|
||||
* or in default resolution mode also if it is not a simple type.
|
||||
*/
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
|
||||
return true;
|
||||
}
|
||||
else if (this.useDefaultResolution) {
|
||||
else if (this.annotationNotRequired) {
|
||||
return !BeanUtils.isSimpleProperty(parameter.getParameterType());
|
||||
}
|
||||
else {
|
||||
@@ -81,13 +84,13 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the argument to a model attribute looking up the attribute in the model or instantiating it using its
|
||||
* default constructor. Data binding and optionally validation is then applied through a {@link WebDataBinder}
|
||||
* instance. Validation is invoked optionally when the method parameter is annotated with an {@code @Valid}.
|
||||
*
|
||||
* @throws BindException if data binding and validation result in an error and the next method parameter
|
||||
* is neither of type {@link Errors} nor {@link BindingResult}.
|
||||
* @throws Exception if a {@link WebDataBinder} could not be created.
|
||||
* Resolve the argument from the model or if not found instantiate it with
|
||||
* its default if it is available. The model attribute is then populated
|
||||
* with request values via data binding and optionally validated
|
||||
* if {@code @java.validation.Valid} is present on the argument.
|
||||
* @throws BindException if data binding and validation result in an error
|
||||
* and the next method parameter is not of type {@link Errors}.
|
||||
* @throws Exception if WebDataBinder initialization fails.
|
||||
*/
|
||||
public final Object resolveArgument(MethodParameter parameter,
|
||||
ModelAndViewContainer mavContainer,
|
||||
@@ -119,16 +122,13 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an instance of the specified model attribute. This method is invoked only if the attribute is
|
||||
* not available in the model. This default implementation uses the no-argument constructor.
|
||||
* Subclasses can override to provide additional means of creating the model attribute.
|
||||
*
|
||||
* @param attributeName the name of the model attribute
|
||||
* @param parameter the method argument declaring the model attribute
|
||||
* @param binderFactory a factory for creating {@link WebDataBinder} instances
|
||||
* Extension point to create the model attribute if not found in the model.
|
||||
* The default implementation uses the default constructor.
|
||||
* @param attributeName the name of the attribute, never {@code null}
|
||||
* @param parameter the method parameter
|
||||
* @param binderFactory for creating WebDataBinder instance
|
||||
* @param request the current request
|
||||
* @return the created model attribute; never {@code null}
|
||||
* @throws Exception raised in the process of creating the instance
|
||||
* @return the created model attribute, never {@code null}
|
||||
*/
|
||||
protected Object createAttribute(String attributeName,
|
||||
MethodParameter parameter,
|
||||
@@ -138,9 +138,8 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the request to the target object contained in the provided binder instance.
|
||||
*
|
||||
* @param binder the binder with the target object to apply request values to
|
||||
* Extension point to bind the request to the target object.
|
||||
* @param binder the data binder instance to use for the binding
|
||||
* @param request the current request
|
||||
*/
|
||||
protected void bindRequestParameters(WebDataBinder binder, NativeWebRequest request) {
|
||||
@@ -148,12 +147,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to validate the given model attribute argument value.
|
||||
* @param argumentValue the validation candidate
|
||||
* @param parameter the method argument declaring the validation candidate
|
||||
* @return {@code true} if validation should be applied, {@code false} otherwise.
|
||||
* Whether to validate the model attribute.
|
||||
* The default implementation checks for {@code @javax.validation.Valid}.
|
||||
* @param modelAttribute the model attribute
|
||||
* @param parameter the method argument
|
||||
*/
|
||||
protected boolean isValidationApplicable(Object argumentValue, MethodParameter parameter) {
|
||||
protected boolean isValidationApplicable(Object modelAttribute, MethodParameter parameter) {
|
||||
Annotation[] annotations = parameter.getParameterAnnotations();
|
||||
for (Annotation annot : annotations) {
|
||||
if ("Valid".equals(annot.annotationType().getSimpleName())) {
|
||||
@@ -164,10 +163,11 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether to raise a {@link BindException} in case of data binding or validation errors.
|
||||
* @param binder the binder on which validation is to be invoked
|
||||
* @param parameter the method argument for which data binding is performed
|
||||
* @return true if the binding or validation errors should result in a {@link BindException}, false otherwise.
|
||||
* Whether to raise a {@link BindException} on bind or validation errors.
|
||||
* The default implementation returns {@code true} if the next method
|
||||
* argument is not of type {@link Errors}.
|
||||
* @param binder the data binder used to perform data binding
|
||||
* @param parameter the method argument
|
||||
*/
|
||||
protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) {
|
||||
int i = parameter.getParameterIndex();
|
||||
@@ -177,10 +177,25 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol
|
||||
return !hasBindingResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return {@code true} if there is a method-level {@code @ModelAttribute}
|
||||
* or if it is a non-simple type when {@code annotationNotRequired=true}.
|
||||
*/
|
||||
public boolean supportsReturnType(MethodParameter returnType) {
|
||||
return returnType.getMethodAnnotation(ModelAttribute.class) != null;
|
||||
if (returnType.getMethodAnnotation(ModelAttribute.class) != null) {
|
||||
return true;
|
||||
}
|
||||
else if (this.annotationNotRequired) {
|
||||
return !BeanUtils.isSimpleProperty(returnType.getParameterType());
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add non-null return values to the {@link ModelAndViewContainer}.
|
||||
*/
|
||||
public void handleReturnValue(Object returnValue,
|
||||
MethodParameter returnType,
|
||||
ModelAndViewContainer mavContainer,
|
||||
|
||||
@@ -25,7 +25,7 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Model} method arguments and handles {@link Model} return values.
|
||||
* Resolves {@link Model} arguments and handles {@link Model} return values.
|
||||
*
|
||||
* <p>A {@link Model} return type has a set purpose. Therefore this handler
|
||||
* should be configured ahead of handlers that support any return value type
|
||||
|
||||
@@ -31,17 +31,17 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link Map} method arguments annotated with an @{@link RequestHeader}.
|
||||
* See {@link RequestHeaderMethodArgumentResolver} for individual header values with an @{@link RequestHeader}.
|
||||
* Resolves {@link Map} method arguments annotated with {@code @RequestHeader}.
|
||||
* For individual header values annotated with {@code @RequestHeader} see
|
||||
* {@link RequestHeaderMethodArgumentResolver} instead.
|
||||
*
|
||||
* <p>The created {@link Map} contains all request header name/value pairs. If the method parameter type
|
||||
* is {@link MultiValueMap} instead, the created map contains all request headers and all their values in case
|
||||
* request headers have multiple values.
|
||||
* <p>The created {@link Map} contains all request header name/value pairs.
|
||||
* The method parameter type may be a {@link MultiValueMap} to receive all
|
||||
* values for a header, not only the first one.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
* @see RequestHeaderMethodArgumentResolver
|
||||
*/
|
||||
public class RequestHeaderMapMethodArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
|
||||
@@ -26,15 +26,16 @@ import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
|
||||
/**
|
||||
* Resolves method arguments annotated with @{@link RequestHeader} with the exception of {@link Map} arguments.
|
||||
* See {@link RequestHeaderMapMethodArgumentResolver} for {@link Map} arguments annotated with @{@link RequestHeader}.
|
||||
* Resolves method arguments annotated with {@code @RequestHeader} except for
|
||||
* {@link Map} arguments. See {@link RequestHeaderMapMethodArgumentResolver} for
|
||||
* details on {@link Map} arguments annotated with {@code @RequestHeader}.
|
||||
*
|
||||
* <p>An @{@link RequestHeader} is a named value that gets resolved from a request header. It has a required flag
|
||||
* and a default value to fall back on when the request header does not exist. See the base class
|
||||
* {@link AbstractNamedValueMethodArgumentResolver} for more information on how named values are processed.
|
||||
* <p>An {@code @RequestHeader} is a named value resolved from a request header.
|
||||
* It has a required flag and a default value to fall back on when the request
|
||||
* header does not exist.
|
||||
*
|
||||
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved request header values that
|
||||
* don't yet match the method parameter type.
|
||||
* <p>A {@link WebDataBinder} is invoked to apply type conversion to resolved
|
||||
* request header values that don't yet match the method parameter type.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Rossen Stoyanchev
|
||||
@@ -43,8 +44,9 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
public class RequestHeaderMethodArgumentResolver extends AbstractNamedValueMethodArgumentResolver {
|
||||
|
||||
/**
|
||||
* @param beanFactory a bean factory to use for resolving ${...} placeholder and #{...} SpEL expressions
|
||||
* in default values, or {@code null} if default values are not expected to contain expressions
|
||||
* @param beanFactory a bean factory to use for resolving ${...}
|
||||
* placeholder and #{...} SpEL expressions in default values;
|
||||
* or {@code null} if default values are not expected to have expressions
|
||||
*/
|
||||
public RequestHeaderMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
|
||||
super(beanFactory);
|
||||
|
||||
@@ -24,8 +24,8 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Resolves {@link SessionStatus} arguments by obtaining it from the
|
||||
* {@link ModelAndViewContainer}.
|
||||
* Resolves a {@link SessionStatus} argument by obtaining it from
|
||||
* the {@link ModelAndViewContainer}.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
|
||||
@@ -137,7 +137,7 @@ public class ModelAttributeMethodProcessorTests {
|
||||
public void supportedReturnTypesInDefaultResolutionMode() throws Exception {
|
||||
processor = new ModelAttributeMethodProcessor(true);
|
||||
assertTrue(processor.supportsReturnType(returnParamNamedModelAttr));
|
||||
assertFalse(processor.supportsReturnType(returnParamNonSimpleType));
|
||||
assertTrue(processor.supportsReturnType(returnParamNonSimpleType));
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user