Drop Portlet MVC support
This commit also removes the corresponding deprecated Servlet MVC variant and updates DispatcherServlet.properties to point to RequestMappingHandlerMapping/Adapter by default. Issue: SPR-14129
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,8 +27,6 @@ import org.springframework.core.annotation.AliasFor;
|
||||
/**
|
||||
* Annotation which indicates that a method parameter should be bound to an HTTP cookie.
|
||||
*
|
||||
* <p>Supported for annotated handler methods in Servlet and Portlet environments.
|
||||
*
|
||||
* <p>The method parameter may be declared as type {@link javax.servlet.http.Cookie}
|
||||
* or as cookie value type (String, int, etc.).
|
||||
*
|
||||
@@ -39,9 +37,6 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @see RequestParam
|
||||
* @see RequestHeader
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -24,8 +24,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation for handling exceptions in specific handler classes and/or
|
||||
* handler methods. Provides consistent style between Servlet and Portlet
|
||||
* environments, with the semantics adapting to the concrete environment.
|
||||
* handler methods.
|
||||
*
|
||||
* <p>Handler methods which are annotated with this annotation are allowed to
|
||||
* have very flexible signatures. They may have parameters of the following
|
||||
@@ -34,16 +33,10 @@ import java.lang.annotation.Target;
|
||||
* <li>An exception argument: declared as a general Exception or as a more
|
||||
* specific exception. This also serves as a mapping hint if the annotation
|
||||
* itself does not narrow the exception types through its {@link #value()}.
|
||||
* <li>Request and/or response objects (Servlet API or Portlet API).
|
||||
* <li>Request and/or response objects (typically from the Servlet API).
|
||||
* You may choose any specific request/response type, e.g.
|
||||
* {@link javax.servlet.ServletRequest} / {@link javax.servlet.http.HttpServletRequest}
|
||||
* or {@link javax.portlet.PortletRequest} / {@link javax.portlet.ActionRequest} /
|
||||
* {@link javax.portlet.RenderRequest}. Note that in the Portlet case,
|
||||
* an explicitly declared action/render argument is also used for mapping
|
||||
* specific request types onto a handler method (in case of no other
|
||||
* information given that differentiates between action and render requests).
|
||||
* <li>Session object (Servlet API or Portlet API): either
|
||||
* {@link javax.servlet.http.HttpSession} or {@link javax.portlet.PortletSession}.
|
||||
* {@link javax.servlet.ServletRequest} / {@link javax.servlet.http.HttpServletRequest}.
|
||||
* <li>Session object: typically {@link javax.servlet.http.HttpSession}.
|
||||
* An argument of this type will enforce the presence of a corresponding session.
|
||||
* As a consequence, such an argument will never be {@code null}.
|
||||
* <i>Note that session access may not be thread-safe, in particular in a
|
||||
@@ -54,17 +47,17 @@ import java.lang.annotation.Target;
|
||||
* <li>{@link org.springframework.web.context.request.WebRequest} or
|
||||
* {@link org.springframework.web.context.request.NativeWebRequest}.
|
||||
* Allows for generic request parameter access as well as request/session
|
||||
* attribute access, without ties to the native Servlet/Portlet API.
|
||||
* attribute access, without ties to the native Servlet API.
|
||||
* <li>{@link java.util.Locale} for the current request locale
|
||||
* (determined by the most specific locale resolver available,
|
||||
* i.e. the configured {@link org.springframework.web.servlet.LocaleResolver}
|
||||
* in a Servlet environment and the portal locale in a Portlet environment).
|
||||
* in a Servlet environment).
|
||||
* <li>{@link java.io.InputStream} / {@link java.io.Reader} for access
|
||||
* to the request's content. This will be the raw InputStream/Reader as
|
||||
* exposed by the Servlet/Portlet API.
|
||||
* exposed by the Servlet API.
|
||||
* <li>{@link java.io.OutputStream} / {@link java.io.Writer} for generating
|
||||
* the response's content. This will be the raw OutputStream/Writer as
|
||||
* exposed by the Servlet/Portlet API.
|
||||
* exposed by the Servlet API.
|
||||
* <li>{@link org.springframework.ui.Model} as an alternative to returning
|
||||
* a model map from the handler method. Note that the provided model is not
|
||||
* pre-populated with regular model attributes and therefore always empty,
|
||||
@@ -73,7 +66,7 @@ import java.lang.annotation.Target;
|
||||
*
|
||||
* <p>The following return types are supported for handler methods:
|
||||
* <ul>
|
||||
* <li>A {@code ModelAndView} object (Servlet MVC or Portlet MVC).
|
||||
* <li>A {@code ModelAndView} object (from Servlet MVC).
|
||||
* <li>A {@link org.springframework.ui.Model} object, with the view name implicitly
|
||||
* determined through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}.
|
||||
* <li>A {@link java.util.Map} object for exposing a model,
|
||||
@@ -93,30 +86,19 @@ import java.lang.annotation.Target;
|
||||
* <li>{@code void} if the method handles the response itself (by
|
||||
* writing the response content directly, declaring an argument of type
|
||||
* {@link javax.servlet.ServletResponse} / {@link javax.servlet.http.HttpServletResponse}
|
||||
* / {@link javax.portlet.RenderResponse} for that purpose)
|
||||
* or if the view name is supposed to be implicitly determined through a
|
||||
* {@link org.springframework.web.servlet.RequestToViewNameTranslator}
|
||||
* (not declaring a response argument in the handler method signature;
|
||||
* only applicable in a Servlet environment).
|
||||
* for that purpose) or if the view name is supposed to be implicitly determined
|
||||
* through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}
|
||||
* (not declaring a response argument in the handler method signature).
|
||||
* </ul>
|
||||
*
|
||||
* <p>In Servlet environments, you can combine the {@code ExceptionHandler} annotation
|
||||
* with {@link ResponseStatus @ResponseStatus}, to define the response status
|
||||
* for the HTTP response.
|
||||
*
|
||||
* <p><b>Note:</b> In Portlet environments, {@code ExceptionHandler} annotated methods
|
||||
* will only be called during the render and resource phases - just like
|
||||
* {@link org.springframework.web.portlet.HandlerExceptionResolver} beans would.
|
||||
* Exceptions carried over from the action and event phases will be invoked during
|
||||
* the render phase as well, with exception handler methods having to be present
|
||||
* on the controller class that defines the applicable <i>render</i> method.
|
||||
*
|
||||
* @author Arjen Poutsma
|
||||
* @author Juergen Hoeller
|
||||
* @since 3.0
|
||||
* @see org.springframework.web.context.request.WebRequest
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerExceptionResolver
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -40,8 +40,6 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @see RequestMapping
|
||||
* @see RequestParam
|
||||
* @see CookieValue
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -27,34 +27,17 @@ import org.springframework.core.annotation.AliasFor;
|
||||
|
||||
/**
|
||||
* Annotation for mapping web requests onto specific handler classes and/or
|
||||
* handler methods. Provides a consistent style between Servlet and Portlet
|
||||
* environments, with the semantics adapting to the concrete environment.
|
||||
*
|
||||
* <p><b>NOTE:</b> The set of features supported for Servlets is a superset
|
||||
* of the set of features supported for Portlets. The places where this applies
|
||||
* are marked with the label "Servlet-only" in this source file. For Servlet
|
||||
* environments there are some further distinctions depending on whether an
|
||||
* application is configured with {@literal "@MVC 3.0"} or
|
||||
* {@literal "@MVC 3.1"} support classes. The places where this applies are
|
||||
* marked with {@literal "@MVC 3.1-only"} in this source file. For more
|
||||
* details see the note on the new support classes added in Spring MVC 3.1
|
||||
* further below.
|
||||
* handler methods.
|
||||
*
|
||||
* <p>Handler methods which are annotated with this annotation are allowed to
|
||||
* have very flexible signatures. They may have parameters of the following
|
||||
* types, in arbitrary order (except for validation results, which need to
|
||||
* follow right after the corresponding command object, if desired):
|
||||
* <ul>
|
||||
* <li>Request and/or response objects (Servlet API or Portlet API).
|
||||
* <li>Request and/or response objects (typically from the Servlet API).
|
||||
* You may choose any specific request/response type, e.g.
|
||||
* {@link javax.servlet.ServletRequest} / {@link javax.servlet.http.HttpServletRequest}
|
||||
* or {@link javax.portlet.PortletRequest} / {@link javax.portlet.ActionRequest} /
|
||||
* {@link javax.portlet.RenderRequest}. Note that in the Portlet case,
|
||||
* an explicitly declared action/render argument is also used for mapping
|
||||
* specific request types onto a handler method (in case of no other
|
||||
* information given that differentiates between action and render requests).
|
||||
* <li>Session object (Servlet API or Portlet API): either
|
||||
* {@link javax.servlet.http.HttpSession} or {@link javax.portlet.PortletSession}.
|
||||
* {@link javax.servlet.ServletRequest} / {@link javax.servlet.http.HttpServletRequest}.
|
||||
* <li>Session object: typically {@link javax.servlet.http.HttpSession}.
|
||||
* An argument of this type will enforce the presence of a corresponding session.
|
||||
* As a consequence, such an argument will never be {@code null}.
|
||||
* <i>Note that session access may not be thread-safe, in particular in a
|
||||
@@ -65,17 +48,17 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* <li>{@link org.springframework.web.context.request.WebRequest} or
|
||||
* {@link org.springframework.web.context.request.NativeWebRequest}.
|
||||
* Allows for generic request parameter access as well as request/session
|
||||
* attribute access, without ties to the native Servlet/Portlet API.
|
||||
* attribute access, without ties to the native Servlet API.
|
||||
* <li>{@link java.util.Locale} for the current request locale
|
||||
* (determined by the most specific locale resolver available,
|
||||
* i.e. the configured {@link org.springframework.web.servlet.LocaleResolver}
|
||||
* in a Servlet environment and the portal locale in a Portlet environment).
|
||||
* in a Servlet environment).
|
||||
* <li>{@link java.io.InputStream} / {@link java.io.Reader} for access
|
||||
* to the request's content. This will be the raw InputStream/Reader as
|
||||
* exposed by the Servlet/Portlet API.
|
||||
* exposed by the Servlet API.
|
||||
* <li>{@link java.io.OutputStream} / {@link java.io.Writer} for generating
|
||||
* the response's content. This will be the raw OutputStream/Writer as
|
||||
* exposed by the Servlet/Portlet API.
|
||||
* exposed by the Servlet API.
|
||||
* <li>{@link org.springframework.http.HttpMethod} for the HTTP request method</li>
|
||||
* <li>{@link PathVariable @PathVariable} annotated parameters (Servlet-only)
|
||||
* for access to URI template values (i.e. /hotels/{hotel}). Variable values will be
|
||||
@@ -94,13 +77,13 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* {@link java.util.Map Map<String, String>} to gain access to all
|
||||
* matrix variables in the URL or to those in a specific path variable.
|
||||
* <li>{@link RequestParam @RequestParam} annotated parameters for access to
|
||||
* specific Servlet/Portlet request parameters. Parameter values will be
|
||||
* specific Servlet request parameters. Parameter values will be
|
||||
* converted to the declared method argument type. Additionally,
|
||||
* {@code @RequestParam} can be used on a {@link java.util.Map Map<String, String>} or
|
||||
* {@link org.springframework.util.MultiValueMap MultiValueMap<String, String>}
|
||||
* method parameter to gain access to all request parameters.
|
||||
* <li>{@link RequestHeader @RequestHeader} annotated parameters for access to
|
||||
* specific Servlet/Portlet request HTTP headers. Parameter values will be
|
||||
* specific Servlet request HTTP headers. Parameter values will be
|
||||
* converted to the declared method argument type. Additionally,
|
||||
* {@code @RequestHeader} can be used on a {@link java.util.Map Map<String, String>},
|
||||
* {@link org.springframework.util.MultiValueMap MultiValueMap<String, String>}, or
|
||||
@@ -177,7 +160,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
*
|
||||
* <p>The following return types are supported for handler methods:
|
||||
* <ul>
|
||||
* <li>A {@code ModelAndView} object (Servlet MVC or Portlet MVC),
|
||||
* <li>A {@code ModelAndView} object (from Servlet MVC),
|
||||
* with the model implicitly enriched with command objects and the results
|
||||
* of {@link ModelAttribute @ModelAttribute} annotated reference data accessor methods.
|
||||
* <li>A {@link org.springframework.ui.Model Model} object, with the view name implicitly
|
||||
@@ -238,11 +221,9 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* <li>{@code void} if the method handles the response itself (by
|
||||
* writing the response content directly, declaring an argument of type
|
||||
* {@link javax.servlet.ServletResponse} / {@link javax.servlet.http.HttpServletResponse}
|
||||
* / {@link javax.portlet.RenderResponse} for that purpose)
|
||||
* or if the view name is supposed to be implicitly determined through a
|
||||
* {@link org.springframework.web.servlet.RequestToViewNameTranslator}
|
||||
* (not declaring a response argument in the handler method signature;
|
||||
* only applicable in a Servlet environment).
|
||||
* for that purpose) or if the view name is supposed to be implicitly determined
|
||||
* through a {@link org.springframework.web.servlet.RequestToViewNameTranslator}
|
||||
* (not declaring a response argument in the handler method signature).
|
||||
* <li>Any other return type will be considered as single model attribute
|
||||
* to be exposed to the view, using the attribute name specified through
|
||||
* {@link ModelAttribute @ModelAttribute} at the method level (or the default attribute
|
||||
@@ -253,9 +234,7 @@ import org.springframework.core.annotation.AliasFor;
|
||||
*
|
||||
* <p><b>NOTE:</b> {@code @RequestMapping} will only be processed if an
|
||||
* an appropriate {@code HandlerMapping}-{@code HandlerAdapter} pair
|
||||
* is configured. This is the case by default in both the
|
||||
* {@code DispatcherServlet} and the {@code DispatcherPortlet}.
|
||||
* However, if you are defining custom {@code HandlerMappings} or
|
||||
* is configured. If you are defining custom {@code HandlerMappings} or
|
||||
* {@code HandlerAdapters}, then you need to add
|
||||
* {@code DefaultAnnotationHandlerMapping} and
|
||||
* {@code AnnotationMethodHandlerAdapter} to your configuration.</code>.
|
||||
@@ -293,8 +272,6 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @see InitBinder
|
||||
* @see org.springframework.web.context.request.WebRequest
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.DefaultAnnotationHandlerMapping
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@@ -314,11 +291,9 @@ public @interface RequestMapping {
|
||||
|
||||
/**
|
||||
* The primary mapping expressed by this annotation.
|
||||
* <p>In a Servlet environment this is an alias for {@link #path}.
|
||||
* For example {@code @RequestMapping("/foo")} is equivalent to
|
||||
* <p>This is an alias for {@link #path}. For example
|
||||
* {@code @RequestMapping("/foo")} is equivalent to
|
||||
* {@code @RequestMapping(path="/foo")}.
|
||||
* <p>In a Portlet environment this is the mapped portlet modes
|
||||
* (i.e. "EDIT", "VIEW", "HELP" or any custom modes).
|
||||
* <p><b>Supported at the type level as well as at the method level!</b>
|
||||
* When used at the type level, all method-level mappings inherit
|
||||
* this primary mapping, narrowing it for a specific handler method.
|
||||
@@ -348,7 +323,6 @@ public @interface RequestMapping {
|
||||
* When used at the type level, all method-level mappings inherit
|
||||
* this HTTP method restriction (i.e. the type-level restriction
|
||||
* gets checked before the handler method is even resolved).
|
||||
* <p>Supported for Servlet environments as well as Portlet 2.0 environments.
|
||||
*/
|
||||
RequestMethod[] method() default {};
|
||||
|
||||
@@ -365,14 +339,10 @@ public @interface RequestMapping {
|
||||
* When used at the type level, all method-level mappings inherit
|
||||
* this parameter restriction (i.e. the type-level restriction
|
||||
* gets checked before the handler method is even resolved).
|
||||
* <p>In a Servlet environment, parameter mappings are considered as restrictions
|
||||
* that are enforced at the type level. The primary path mapping (i.e. the
|
||||
* specified URI value) still has to uniquely identify the target handler, with
|
||||
* parameter mappings simply expressing preconditions for invoking the handler.
|
||||
* <p>In a Portlet environment, parameters are taken into account as mapping
|
||||
* differentiators, i.e. the primary portlet mode mapping plus the parameter
|
||||
* conditions uniquely identify the target handler. Different handlers may be
|
||||
* mapped onto the same portlet mode, as long as their parameter mappings differ.
|
||||
* <p>Parameter mappings are considered as restrictions that are enforced at
|
||||
* the type level. The primary path mapping (i.e. the specified URI value)
|
||||
* still has to uniquely identify the target handler, with parameter mappings
|
||||
* simply expressing preconditions for invoking the handler.
|
||||
*/
|
||||
String[] params() default {};
|
||||
|
||||
@@ -395,8 +365,6 @@ public @interface RequestMapping {
|
||||
* When used at the type level, all method-level mappings inherit
|
||||
* this header restriction (i.e. the type-level restriction
|
||||
* gets checked before the handler method is even resolved).
|
||||
* <p>Maps against HttpServletRequest headers in a Servlet environment,
|
||||
* and against PortletRequest properties in a Portlet 2.0 environment.
|
||||
* @see org.springframework.http.MediaType
|
||||
*/
|
||||
String[] headers() default {};
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,9 +47,6 @@ import org.springframework.core.annotation.AliasFor;
|
||||
* @see RequestMapping
|
||||
* @see RequestHeader
|
||||
* @see CookieValue
|
||||
* @see org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter
|
||||
*/
|
||||
@Target(ElementType.PARAMETER)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.bind.annotation.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.core.NestedRuntimeException;
|
||||
|
||||
/**
|
||||
* Exception indicating that the execution of an annotated MVC handler method failed.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.6
|
||||
* @see HandlerMethodInvoker#invokeHandlerMethod
|
||||
* @deprecated as of 4.3, in favor of the {@code HandlerMethod}-based MVC infrastructure
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("serial")
|
||||
public class HandlerMethodInvocationException extends NestedRuntimeException {
|
||||
|
||||
/**
|
||||
* Create a new HandlerMethodInvocationException for the given Method handle and cause.
|
||||
* @param handlerMethod the handler method handle
|
||||
* @param cause the cause of the invocation failure
|
||||
*/
|
||||
public HandlerMethodInvocationException(Method handlerMethod, Throwable cause) {
|
||||
super("Failed to invoke handler method [" + handlerMethod + "]", cause);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,901 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.bind.annotation.support;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Array;
|
||||
import java.lang.reflect.GenericArrayType;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.ParameterNameDiscoverer;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.SynthesizingMethodParameter;
|
||||
import org.springframework.http.HttpEntity;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpInputMessage;
|
||||
import org.springframework.http.HttpOutputMessage;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.converter.HttpMessageConverter;
|
||||
import org.springframework.ui.ExtendedModelMap;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.validation.Errors;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.HttpMediaTypeNotSupportedException;
|
||||
import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.CookieValue;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestHeader;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ValueConstants;
|
||||
import org.springframework.web.bind.support.DefaultSessionAttributeStore;
|
||||
import org.springframework.web.bind.support.SessionAttributeStore;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
import org.springframework.web.bind.support.SimpleSessionStatus;
|
||||
import org.springframework.web.bind.support.WebArgumentResolver;
|
||||
import org.springframework.web.bind.support.WebBindingInitializer;
|
||||
import org.springframework.web.bind.support.WebRequestDataBinder;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import org.springframework.web.multipart.MultipartRequest;
|
||||
|
||||
/**
|
||||
* Support class for invoking an annotated handler method. Operates on the introspection
|
||||
* results of a {@link HandlerMethodResolver} for a specific handler type.
|
||||
*
|
||||
* <p>Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
|
||||
* and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
* @since 2.5.2
|
||||
* @see #invokeHandlerMethod
|
||||
* @deprecated as of 4.3, in favor of the {@code HandlerMethod}-based MVC infrastructure
|
||||
*/
|
||||
@Deprecated
|
||||
public class HandlerMethodInvoker {
|
||||
|
||||
private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE.";
|
||||
|
||||
/** We'll create a lot of these objects, so we don't want a new logger every time. */
|
||||
private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class);
|
||||
|
||||
private final HandlerMethodResolver methodResolver;
|
||||
|
||||
private final WebBindingInitializer bindingInitializer;
|
||||
|
||||
private final SessionAttributeStore sessionAttributeStore;
|
||||
|
||||
private final ParameterNameDiscoverer parameterNameDiscoverer;
|
||||
|
||||
private final WebArgumentResolver[] customArgumentResolvers;
|
||||
|
||||
private final HttpMessageConverter<?>[] messageConverters;
|
||||
|
||||
private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus();
|
||||
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver) {
|
||||
this(methodResolver, null);
|
||||
}
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) {
|
||||
this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null);
|
||||
}
|
||||
|
||||
public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer,
|
||||
SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer,
|
||||
WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter<?>[] messageConverters) {
|
||||
|
||||
this.methodResolver = methodResolver;
|
||||
this.bindingInitializer = bindingInitializer;
|
||||
this.sessionAttributeStore = sessionAttributeStore;
|
||||
this.parameterNameDiscoverer = parameterNameDiscoverer;
|
||||
this.customArgumentResolvers = customArgumentResolvers;
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
|
||||
public final Object invokeHandlerMethod(Method handlerMethod, Object handler,
|
||||
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
|
||||
|
||||
Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod);
|
||||
try {
|
||||
boolean debug = logger.isDebugEnabled();
|
||||
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
|
||||
Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName);
|
||||
if (attrValue != null) {
|
||||
implicitModel.addAttribute(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) {
|
||||
Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod);
|
||||
Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel);
|
||||
if (debug) {
|
||||
logger.debug("Invoking model attribute method: " + attributeMethodToInvoke);
|
||||
}
|
||||
String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value();
|
||||
if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) {
|
||||
continue;
|
||||
}
|
||||
ReflectionUtils.makeAccessible(attributeMethodToInvoke);
|
||||
Object attrValue = attributeMethodToInvoke.invoke(handler, args);
|
||||
if ("".equals(attrName)) {
|
||||
Class<?> resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass());
|
||||
attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue);
|
||||
}
|
||||
if (!implicitModel.containsAttribute(attrName)) {
|
||||
implicitModel.addAttribute(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel);
|
||||
if (debug) {
|
||||
logger.debug("Invoking request handler method: " + handlerMethodToInvoke);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(handlerMethodToInvoke);
|
||||
return handlerMethodToInvoke.invoke(handler, args);
|
||||
}
|
||||
catch (IllegalStateException ex) {
|
||||
// Internal assertion failed (e.g. invalid signature):
|
||||
// throw exception with full handler method context...
|
||||
throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex);
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
// User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception...
|
||||
ReflectionUtils.rethrowException(ex.getTargetException());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public final void updateModelAttributes(Object handler, Map<String, Object> mavModel,
|
||||
ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) {
|
||||
for (String attrName : this.methodResolver.getActualSessionAttributeNames()) {
|
||||
this.sessionAttributeStore.cleanupAttribute(webRequest, attrName);
|
||||
}
|
||||
}
|
||||
|
||||
// Expose model attributes as session attributes, if required.
|
||||
// Expose BindingResults for all attributes, making custom editors available.
|
||||
Map<String, Object> model = (mavModel != null ? mavModel : implicitModel);
|
||||
if (model != null) {
|
||||
try {
|
||||
String[] originalAttrNames = model.keySet().toArray(new String[model.size()]);
|
||||
for (String attrName : originalAttrNames) {
|
||||
Object attrValue = model.get(attrName);
|
||||
boolean isSessionAttr = this.methodResolver.isSessionAttribute(
|
||||
attrName, (attrValue != null ? attrValue.getClass() : null));
|
||||
if (isSessionAttr) {
|
||||
if (this.sessionStatus.isComplete()) {
|
||||
implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE);
|
||||
}
|
||||
else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) {
|
||||
this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue);
|
||||
}
|
||||
}
|
||||
if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) &&
|
||||
(isSessionAttr || isBindingCandidate(attrValue))) {
|
||||
String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName;
|
||||
if (mavModel != null && !model.containsKey(bindingResultKey)) {
|
||||
WebDataBinder binder = createBinder(webRequest, attrValue, attrName);
|
||||
initBinder(handler, attrName, binder, webRequest);
|
||||
mavModel.put(bindingResultKey, binder.getBindingResult());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (InvocationTargetException ex) {
|
||||
// User-defined @InitBinder method threw an exception...
|
||||
ReflectionUtils.rethrowException(ex.getTargetException());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Object[] resolveHandlerArguments(Method handlerMethod, Object handler,
|
||||
NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception {
|
||||
|
||||
Class<?>[] paramTypes = handlerMethod.getParameterTypes();
|
||||
Object[] args = new Object[paramTypes.length];
|
||||
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
MethodParameter methodParam = new SynthesizingMethodParameter(handlerMethod, i);
|
||||
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
|
||||
String paramName = null;
|
||||
String headerName = null;
|
||||
boolean requestBodyFound = false;
|
||||
String cookieName = null;
|
||||
String pathVarName = null;
|
||||
String attrName = null;
|
||||
boolean required = false;
|
||||
String defaultValue = null;
|
||||
boolean validate = false;
|
||||
Object[] validationHints = null;
|
||||
int annotationsFound = 0;
|
||||
Annotation[] paramAnns = methodParam.getParameterAnnotations();
|
||||
|
||||
for (Annotation paramAnn : paramAnns) {
|
||||
if (RequestParam.class.isInstance(paramAnn)) {
|
||||
RequestParam requestParam = (RequestParam) paramAnn;
|
||||
paramName = requestParam.name();
|
||||
required = requestParam.required();
|
||||
defaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (RequestHeader.class.isInstance(paramAnn)) {
|
||||
RequestHeader requestHeader = (RequestHeader) paramAnn;
|
||||
headerName = requestHeader.name();
|
||||
required = requestHeader.required();
|
||||
defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue());
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (RequestBody.class.isInstance(paramAnn)) {
|
||||
requestBodyFound = true;
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (CookieValue.class.isInstance(paramAnn)) {
|
||||
CookieValue cookieValue = (CookieValue) paramAnn;
|
||||
cookieName = cookieValue.name();
|
||||
required = cookieValue.required();
|
||||
defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue());
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (PathVariable.class.isInstance(paramAnn)) {
|
||||
PathVariable pathVar = (PathVariable) paramAnn;
|
||||
pathVarName = pathVar.value();
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (ModelAttribute.class.isInstance(paramAnn)) {
|
||||
ModelAttribute attr = (ModelAttribute) paramAnn;
|
||||
attrName = attr.value();
|
||||
annotationsFound++;
|
||||
}
|
||||
else if (Value.class.isInstance(paramAnn)) {
|
||||
defaultValue = ((Value) paramAnn).value();
|
||||
}
|
||||
else {
|
||||
Validated validatedAnn = AnnotationUtils.getAnnotation(paramAnn, Validated.class);
|
||||
if (validatedAnn != null || paramAnn.annotationType().getSimpleName().startsWith("Valid")) {
|
||||
validate = true;
|
||||
Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(paramAnn));
|
||||
validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[]{hints});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (annotationsFound > 1) {
|
||||
throw new IllegalStateException("Handler parameter annotations are exclusive choices - " +
|
||||
"do not specify more than one such annotation on the same parameter: " + handlerMethod);
|
||||
}
|
||||
|
||||
if (annotationsFound == 0) {
|
||||
Object argValue = resolveCommonArgument(methodParam, webRequest);
|
||||
if (argValue != WebArgumentResolver.UNRESOLVED) {
|
||||
args[i] = argValue;
|
||||
}
|
||||
else if (defaultValue != null) {
|
||||
args[i] = resolveDefaultValue(defaultValue);
|
||||
}
|
||||
else {
|
||||
Class<?> paramType = methodParam.getParameterType();
|
||||
if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) {
|
||||
if (!paramType.isAssignableFrom(implicitModel.getClass())) {
|
||||
throw new IllegalStateException("Argument [" + paramType.getSimpleName() + "] is of type " +
|
||||
"Model or Map but is not assignable from the actual model. You may need to switch " +
|
||||
"newer MVC infrastructure classes to use this argument.");
|
||||
}
|
||||
args[i] = implicitModel;
|
||||
}
|
||||
else if (SessionStatus.class.isAssignableFrom(paramType)) {
|
||||
args[i] = this.sessionStatus;
|
||||
}
|
||||
else if (HttpEntity.class.isAssignableFrom(paramType)) {
|
||||
args[i] = resolveHttpEntityRequest(methodParam, webRequest);
|
||||
}
|
||||
else if (Errors.class.isAssignableFrom(paramType)) {
|
||||
throw new IllegalStateException("Errors/BindingResult argument declared " +
|
||||
"without preceding model attribute. Check your handler method signature!");
|
||||
}
|
||||
else if (BeanUtils.isSimpleProperty(paramType)) {
|
||||
paramName = "";
|
||||
}
|
||||
else {
|
||||
attrName = "";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paramName != null) {
|
||||
args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (headerName != null) {
|
||||
args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (requestBodyFound) {
|
||||
args[i] = resolveRequestBody(methodParam, webRequest, handler);
|
||||
}
|
||||
else if (cookieName != null) {
|
||||
args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (pathVarName != null) {
|
||||
args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler);
|
||||
}
|
||||
else if (attrName != null) {
|
||||
WebDataBinder binder =
|
||||
resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler);
|
||||
boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1]));
|
||||
if (binder.getTarget() != null) {
|
||||
doBind(binder, webRequest, validate, validationHints, !assignBindingResult);
|
||||
}
|
||||
args[i] = binder.getTarget();
|
||||
if (assignBindingResult) {
|
||||
args[i + 1] = binder.getBindingResult();
|
||||
i++;
|
||||
}
|
||||
implicitModel.putAll(binder.getBindingResult().getModel());
|
||||
}
|
||||
}
|
||||
|
||||
return args;
|
||||
}
|
||||
|
||||
protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
if (this.bindingInitializer != null) {
|
||||
this.bindingInitializer.initBinder(binder, webRequest);
|
||||
}
|
||||
if (handler != null) {
|
||||
Set<Method> initBinderMethods = this.methodResolver.getInitBinderMethods();
|
||||
if (!initBinderMethods.isEmpty()) {
|
||||
boolean debug = logger.isDebugEnabled();
|
||||
for (Method initBinderMethod : initBinderMethods) {
|
||||
Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod);
|
||||
String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value();
|
||||
if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) {
|
||||
Object[] initBinderArgs =
|
||||
resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest);
|
||||
if (debug) {
|
||||
logger.debug("Invoking init-binder method: " + methodToInvoke);
|
||||
}
|
||||
ReflectionUtils.makeAccessible(methodToInvoke);
|
||||
Object returnValue = methodToInvoke.invoke(handler, initBinderArgs);
|
||||
if (returnValue != null) {
|
||||
throw new IllegalStateException(
|
||||
"InitBinder methods must not have a return value: " + methodToInvoke);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod,
|
||||
WebDataBinder binder, NativeWebRequest webRequest) throws Exception {
|
||||
|
||||
Class<?>[] initBinderParams = initBinderMethod.getParameterTypes();
|
||||
Object[] initBinderArgs = new Object[initBinderParams.length];
|
||||
|
||||
for (int i = 0; i < initBinderArgs.length; i++) {
|
||||
MethodParameter methodParam = new SynthesizingMethodParameter(initBinderMethod, i);
|
||||
methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer);
|
||||
GenericTypeResolver.resolveParameterType(methodParam, handler.getClass());
|
||||
String paramName = null;
|
||||
boolean paramRequired = false;
|
||||
String paramDefaultValue = null;
|
||||
String pathVarName = null;
|
||||
Annotation[] paramAnns = methodParam.getParameterAnnotations();
|
||||
|
||||
for (Annotation paramAnn : paramAnns) {
|
||||
if (RequestParam.class.isInstance(paramAnn)) {
|
||||
RequestParam requestParam = (RequestParam) paramAnn;
|
||||
paramName = requestParam.name();
|
||||
paramRequired = requestParam.required();
|
||||
paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue());
|
||||
break;
|
||||
}
|
||||
else if (ModelAttribute.class.isInstance(paramAnn)) {
|
||||
throw new IllegalStateException(
|
||||
"@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod);
|
||||
}
|
||||
else if (PathVariable.class.isInstance(paramAnn)) {
|
||||
PathVariable pathVar = (PathVariable) paramAnn;
|
||||
pathVarName = pathVar.value();
|
||||
}
|
||||
}
|
||||
|
||||
if (paramName == null && pathVarName == null) {
|
||||
Object argValue = resolveCommonArgument(methodParam, webRequest);
|
||||
if (argValue != WebArgumentResolver.UNRESOLVED) {
|
||||
initBinderArgs[i] = argValue;
|
||||
}
|
||||
else {
|
||||
Class<?> paramType = initBinderParams[i];
|
||||
if (paramType.isInstance(binder)) {
|
||||
initBinderArgs[i] = binder;
|
||||
}
|
||||
else if (BeanUtils.isSimpleProperty(paramType)) {
|
||||
paramName = "";
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Unsupported argument [" + paramType.getName() +
|
||||
"] for @InitBinder method: " + initBinderMethod);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (paramName != null) {
|
||||
initBinderArgs[i] =
|
||||
resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null);
|
||||
}
|
||||
else if (pathVarName != null) {
|
||||
initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null);
|
||||
}
|
||||
}
|
||||
|
||||
return initBinderArgs;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object resolveRequestParam(String paramName, boolean required, String defaultValue,
|
||||
MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = methodParam.getParameterType();
|
||||
if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) {
|
||||
return resolveRequestParamMap((Class<? extends Map<?, ?>>) paramType, webRequest);
|
||||
}
|
||||
if (paramName.length() == 0) {
|
||||
paramName = getRequiredParameterName(methodParam);
|
||||
}
|
||||
Object paramValue = null;
|
||||
MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class);
|
||||
if (multipartRequest != null) {
|
||||
List<MultipartFile> files = multipartRequest.getFiles(paramName);
|
||||
if (!files.isEmpty()) {
|
||||
paramValue = (files.size() == 1 ? files.get(0) : files);
|
||||
}
|
||||
}
|
||||
if (paramValue == null) {
|
||||
String[] paramValues = webRequest.getParameterValues(paramName);
|
||||
if (paramValues != null) {
|
||||
paramValue = (paramValues.length == 1 ? paramValues[0] : paramValues);
|
||||
}
|
||||
}
|
||||
if (paramValue == null) {
|
||||
if (defaultValue != null) {
|
||||
paramValue = resolveDefaultValue(defaultValue);
|
||||
}
|
||||
else if (required) {
|
||||
raiseMissingParameterException(paramName, paramType);
|
||||
}
|
||||
paramValue = checkValue(paramName, paramValue, paramType);
|
||||
}
|
||||
WebDataBinder binder = createBinder(webRequest, null, paramName);
|
||||
initBinder(handlerForInitBinderCall, paramName, binder, webRequest);
|
||||
return binder.convertIfNecessary(paramValue, paramType, methodParam);
|
||||
}
|
||||
|
||||
private Map<String, ?> resolveRequestParamMap(Class<? extends Map<?, ?>> mapType, NativeWebRequest webRequest) {
|
||||
Map<String, String[]> parameterMap = webRequest.getParameterMap();
|
||||
if (MultiValueMap.class.isAssignableFrom(mapType)) {
|
||||
MultiValueMap<String, String> result = new LinkedMultiValueMap<String, String>(parameterMap.size());
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
for (String value : entry.getValue()) {
|
||||
result.add(entry.getKey(), value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
Map<String, String> result = new LinkedHashMap<String, String>(parameterMap.size());
|
||||
for (Map.Entry<String, String[]> entry : parameterMap.entrySet()) {
|
||||
if (entry.getValue().length > 0) {
|
||||
result.put(entry.getKey(), entry.getValue()[0]);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Object resolveRequestHeader(String headerName, boolean required, String defaultValue,
|
||||
MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall)
|
||||
throws Exception {
|
||||
|
||||
Class<?> paramType = methodParam.getParameterType();
|
||||
if (Map.class.isAssignableFrom(paramType)) {
|
||||
return resolveRequestHeaderMap((Class<? extends Map<?, ?>>) paramType, webRequest);
|
||||
}
|
||||
if (headerName.length() == 0) {
|
||||
headerName = getRequiredParameterName(methodParam);
|
||||
}
|
||||
Object headerValue = null;
|
||||
String[] headerValues = webRequest.getHeaderValues(headerName);
|
||||
if (headerValues != null) {
|
||||
headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues);
|
||||
}
|
||||
if (headerValue == null) {
|
||||
if (defaultValue != null) {
|
||||
headerValue = resolveDefaultValue(defaultValue);
|
||||
}
|
||||
else if (required) {
|
||||
raiseMissingHeaderException(headerName, paramType);
|
||||
}
|
||||
headerValue = checkValue(headerName, headerValue, paramType);
|
||||
}
|
||||
WebDataBinder binder = createBinder(webRequest, null, headerName);
|
||||
initBinder(handlerForInitBinderCall, headerName, binder, webRequest);
|
||||
return binder.convertIfNecessary(headerValue, paramType, methodParam);
|
||||
}
|
||||
|
||||
private Map<String, ?> resolveRequestHeaderMap(Class<? extends Map<?, ?>> mapType, NativeWebRequest webRequest) {
|
||||
if (MultiValueMap.class.isAssignableFrom(mapType)) {
|
||||
MultiValueMap<String, String> result;
|
||||
if (HttpHeaders.class.isAssignableFrom(mapType)) {
|
||||
result = new HttpHeaders();
|
||||
}
|
||||
else {
|
||||
result = new LinkedMultiValueMap<String, String>();
|
||||
}
|
||||
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
|
||||
String headerName = iterator.next();
|
||||
for (String headerValue : webRequest.getHeaderValues(headerName)) {
|
||||
result.add(headerName, headerValue);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
else {
|
||||
Map<String, String> result = new LinkedHashMap<String, String>();
|
||||
for (Iterator<String> iterator = webRequest.getHeaderNames(); iterator.hasNext();) {
|
||||
String headerName = iterator.next();
|
||||
String headerValue = webRequest.getHeader(headerName);
|
||||
result.put(headerName, headerValue);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given {@link RequestBody @RequestBody} annotation.
|
||||
*/
|
||||
protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler)
|
||||
throws Exception {
|
||||
|
||||
return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType());
|
||||
}
|
||||
|
||||
private HttpEntity<?> resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
HttpInputMessage inputMessage = createHttpInputMessage(webRequest);
|
||||
Class<?> paramType = getHttpEntityType(methodParam);
|
||||
Object body = readWithMessageConverters(methodParam, inputMessage, paramType);
|
||||
return new HttpEntity<Object>(body, inputMessage.getHeaders());
|
||||
}
|
||||
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class<?> paramType)
|
||||
throws Exception {
|
||||
|
||||
MediaType contentType = inputMessage.getHeaders().getContentType();
|
||||
if (contentType == null) {
|
||||
StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType()));
|
||||
String paramName = methodParam.getParameterName();
|
||||
if (paramName != null) {
|
||||
builder.append(' ');
|
||||
builder.append(paramName);
|
||||
}
|
||||
throw new HttpMediaTypeNotSupportedException(
|
||||
"Cannot extract parameter (" + builder.toString() + "): no Content-Type found");
|
||||
}
|
||||
|
||||
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
|
||||
if (this.messageConverters != null) {
|
||||
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
|
||||
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
|
||||
if (messageConverter.canRead(paramType, contentType)) {
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType
|
||||
+"\" using [" + messageConverter + "]");
|
||||
}
|
||||
return messageConverter.read((Class) paramType, inputMessage);
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
|
||||
}
|
||||
|
||||
private Class<?> getHttpEntityType(MethodParameter methodParam) {
|
||||
Assert.isAssignable(HttpEntity.class, methodParam.getParameterType());
|
||||
ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType();
|
||||
if (type.getActualTypeArguments().length == 1) {
|
||||
Type typeArgument = type.getActualTypeArguments()[0];
|
||||
if (typeArgument instanceof Class) {
|
||||
return (Class<?>) typeArgument;
|
||||
}
|
||||
else if (typeArgument instanceof GenericArrayType) {
|
||||
Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType();
|
||||
if (componentType instanceof Class) {
|
||||
// Surely, there should be a nicer way to do this
|
||||
Object array = Array.newInstance((Class<?>) componentType, 0);
|
||||
return array.getClass();
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized");
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
cookieName = getRequiredParameterName(methodParam);
|
||||
}
|
||||
Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest);
|
||||
if (cookieValue == null) {
|
||||
if (defaultValue != null) {
|
||||
cookieValue = resolveDefaultValue(defaultValue);
|
||||
}
|
||||
else if (required) {
|
||||
raiseMissingCookieException(cookieName, paramType);
|
||||
}
|
||||
cookieValue = checkValue(cookieName, cookieValue, paramType);
|
||||
}
|
||||
WebDataBinder binder = createBinder(webRequest, null, cookieName);
|
||||
initBinder(handlerForInitBinderCall, cookieName, binder, webRequest);
|
||||
return binder.convertIfNecessary(cookieValue, paramType, methodParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given {@link CookieValue @CookieValue} annotation.
|
||||
* <p>Throws an UnsupportedOperationException by default.
|
||||
*/
|
||||
protected Object resolveCookieValue(String cookieName, Class<?> paramType, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
throw new UnsupportedOperationException("@CookieValue not supported");
|
||||
}
|
||||
|
||||
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);
|
||||
WebDataBinder binder = createBinder(webRequest, null, pathVarName);
|
||||
initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest);
|
||||
return binder.convertIfNecessary(pathVarValue, paramType, methodParam);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolves the given {@link PathVariable @PathVariable} annotation.
|
||||
* <p>Throws an UnsupportedOperationException by default.
|
||||
*/
|
||||
protected String resolvePathVariable(String pathVarName, Class<?> paramType, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
throw new UnsupportedOperationException("@PathVariable not supported");
|
||||
}
|
||||
|
||||
private String getRequiredParameterName(MethodParameter methodParam) {
|
||||
String name = methodParam.getParameterName();
|
||||
if (name == null) {
|
||||
throw new IllegalStateException(
|
||||
"No parameter name specified for argument of type [" + methodParam.getParameterType().getName() +
|
||||
"], and no parameter name information found in class file either.");
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
private Object checkValue(String name, Object value, Class<?> paramType) {
|
||||
if (value == null) {
|
||||
if (boolean.class == paramType) {
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
else if (paramType.isPrimitive()) {
|
||||
throw new IllegalStateException("Optional " + paramType + " parameter '" + name +
|
||||
"' is not present but cannot be translated into a null value due to being declared as a " +
|
||||
"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam,
|
||||
ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception {
|
||||
|
||||
// Bind request parameter onto object...
|
||||
String name = attrName;
|
||||
if ("".equals(name)) {
|
||||
name = Conventions.getVariableNameForParameter(methodParam);
|
||||
}
|
||||
Class<?> paramType = methodParam.getParameterType();
|
||||
Object bindObject;
|
||||
if (implicitModel.containsKey(name)) {
|
||||
bindObject = implicitModel.get(name);
|
||||
}
|
||||
else if (this.methodResolver.isSessionAttribute(name, paramType)) {
|
||||
bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name);
|
||||
if (bindObject == null) {
|
||||
raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session");
|
||||
}
|
||||
}
|
||||
else {
|
||||
bindObject = BeanUtils.instantiateClass(paramType);
|
||||
}
|
||||
WebDataBinder binder = createBinder(webRequest, bindObject, name);
|
||||
initBinder(handler, name, binder, webRequest);
|
||||
return binder;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to
|
||||
* bean-style data binding later on.
|
||||
*/
|
||||
protected boolean isBindingCandidate(Object value) {
|
||||
return (value != null && !value.getClass().isArray() && !(value instanceof Collection) &&
|
||||
!(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass()));
|
||||
}
|
||||
|
||||
protected void raiseMissingParameterException(String paramName, Class<?> paramType) throws Exception {
|
||||
throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]");
|
||||
}
|
||||
|
||||
protected void raiseMissingHeaderException(String headerName, Class<?> paramType) throws Exception {
|
||||
throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]");
|
||||
}
|
||||
|
||||
protected void raiseMissingCookieException(String cookieName, Class<?> paramType) throws Exception {
|
||||
throw new IllegalStateException(
|
||||
"Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]");
|
||||
}
|
||||
|
||||
protected void raiseSessionRequiredException(String message) throws Exception {
|
||||
throw new IllegalStateException(message);
|
||||
}
|
||||
|
||||
protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName)
|
||||
throws Exception {
|
||||
|
||||
return new WebRequestDataBinder(target, objectName);
|
||||
}
|
||||
|
||||
private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate,
|
||||
Object[] validationHints, boolean failOnErrors) throws Exception {
|
||||
|
||||
doBind(binder, webRequest);
|
||||
if (validate) {
|
||||
binder.validate(validationHints);
|
||||
}
|
||||
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 UnsupportedOperation1Exception by default.
|
||||
*/
|
||||
protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
throw new UnsupportedOperationException("@RequestBody not supported");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}.
|
||||
* <p>Throws an UnsupportedOperationException by default.
|
||||
*/
|
||||
protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception {
|
||||
throw new UnsupportedOperationException("@Body not supported");
|
||||
}
|
||||
|
||||
protected String parseDefaultValueAttribute(String value) {
|
||||
return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value);
|
||||
}
|
||||
|
||||
protected Object resolveDefaultValue(String value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest)
|
||||
throws Exception {
|
||||
|
||||
// Invoke custom argument resolvers if present...
|
||||
if (this.customArgumentResolvers != null) {
|
||||
for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) {
|
||||
Object value = argumentResolver.resolveArgument(methodParameter, webRequest);
|
||||
if (value != WebArgumentResolver.UNRESOLVED) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Resolution of standard parameter types...
|
||||
Class<?> paramType = methodParameter.getParameterType();
|
||||
Object value = resolveStandardArgument(paramType, webRequest);
|
||||
if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) {
|
||||
throw new IllegalStateException("Standard argument type [" + paramType.getName() +
|
||||
"] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) +
|
||||
"]. Consider declaring the argument type in a less specific fashion.");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,172 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.web.bind.annotation.support;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.web.bind.annotation.InitBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
|
||||
/**
|
||||
* Support class for resolving web method annotations in a handler type.
|
||||
* Processes {@code @RequestMapping}, {@code @InitBinder},
|
||||
* {@code @ModelAttribute} and {@code @SessionAttributes}.
|
||||
*
|
||||
* <p>Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter}
|
||||
* and {@link org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
* @see org.springframework.web.bind.annotation.RequestMapping
|
||||
* @see org.springframework.web.bind.annotation.InitBinder
|
||||
* @see org.springframework.web.bind.annotation.ModelAttribute
|
||||
* @see org.springframework.web.bind.annotation.SessionAttributes
|
||||
* @deprecated as of 4.3, in favor of the {@code HandlerMethod}-based MVC infrastructure
|
||||
*/
|
||||
@Deprecated
|
||||
public class HandlerMethodResolver {
|
||||
|
||||
private final Set<Method> handlerMethods = new LinkedHashSet<Method>();
|
||||
|
||||
private final Set<Method> initBinderMethods = new LinkedHashSet<Method>();
|
||||
|
||||
private final Set<Method> modelAttributeMethods = new LinkedHashSet<Method>();
|
||||
|
||||
private RequestMapping typeLevelMapping;
|
||||
|
||||
private boolean sessionAttributesFound;
|
||||
|
||||
private final Set<String> sessionAttributeNames = new HashSet<String>();
|
||||
|
||||
private final Set<Class<?>> sessionAttributeTypes = new HashSet<Class<?>>();
|
||||
|
||||
private final Set<String> actualSessionAttributeNames =
|
||||
Collections.newSetFromMap(new ConcurrentHashMap<String, Boolean>(4));
|
||||
|
||||
|
||||
/**
|
||||
* Initialize a new HandlerMethodResolver for the specified handler type.
|
||||
* @param handlerType the handler class to introspect
|
||||
*/
|
||||
public void init(final Class<?> handlerType) {
|
||||
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
|
||||
Class<?> specificHandlerType = null;
|
||||
if (!Proxy.isProxyClass(handlerType)) {
|
||||
handlerTypes.add(handlerType);
|
||||
specificHandlerType = handlerType;
|
||||
}
|
||||
handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
|
||||
for (Class<?> currentHandlerType : handlerTypes) {
|
||||
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
|
||||
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
if (isHandlerMethod(specificMethod) &&
|
||||
(bridgedMethod == specificMethod || !isHandlerMethod(bridgedMethod))) {
|
||||
handlerMethods.add(specificMethod);
|
||||
}
|
||||
else if (isInitBinderMethod(specificMethod) &&
|
||||
(bridgedMethod == specificMethod || !isInitBinderMethod(bridgedMethod))) {
|
||||
initBinderMethods.add(specificMethod);
|
||||
}
|
||||
else if (isModelAttributeMethod(specificMethod) &&
|
||||
(bridgedMethod == specificMethod || !isModelAttributeMethod(bridgedMethod))) {
|
||||
modelAttributeMethods.add(specificMethod);
|
||||
}
|
||||
}
|
||||
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||
}
|
||||
this.typeLevelMapping = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
|
||||
SessionAttributes sessionAttributes = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
|
||||
this.sessionAttributesFound = (sessionAttributes != null);
|
||||
if (this.sessionAttributesFound) {
|
||||
this.sessionAttributeNames.addAll(Arrays.asList(sessionAttributes.names()));
|
||||
this.sessionAttributeTypes.addAll(Arrays.asList(sessionAttributes.types()));
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isHandlerMethod(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, RequestMapping.class) != null;
|
||||
}
|
||||
|
||||
protected boolean isInitBinderMethod(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
|
||||
}
|
||||
|
||||
protected boolean isModelAttributeMethod(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, ModelAttribute.class) != null;
|
||||
}
|
||||
|
||||
|
||||
public final boolean hasHandlerMethods() {
|
||||
return !this.handlerMethods.isEmpty();
|
||||
}
|
||||
|
||||
public final Set<Method> getHandlerMethods() {
|
||||
return this.handlerMethods;
|
||||
}
|
||||
|
||||
public final Set<Method> getInitBinderMethods() {
|
||||
return this.initBinderMethods;
|
||||
}
|
||||
|
||||
public final Set<Method> getModelAttributeMethods() {
|
||||
return this.modelAttributeMethods;
|
||||
}
|
||||
|
||||
public boolean hasTypeLevelMapping() {
|
||||
return (this.typeLevelMapping != null);
|
||||
}
|
||||
|
||||
public RequestMapping getTypeLevelMapping() {
|
||||
return this.typeLevelMapping;
|
||||
}
|
||||
|
||||
public boolean hasSessionAttributes() {
|
||||
return this.sessionAttributesFound;
|
||||
}
|
||||
|
||||
public boolean isSessionAttribute(String attrName, Class<?> attrType) {
|
||||
if (this.sessionAttributeNames.contains(attrName) || this.sessionAttributeTypes.contains(attrType)) {
|
||||
this.actualSessionAttributeNames.add(attrName);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Set<String> getActualSessionAttributeNames() {
|
||||
return this.actualSessionAttributeNames;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
/**
|
||||
* Support classes for web annotation processing.
|
||||
*/
|
||||
package org.springframework.web.bind.annotation.support;
|
||||
@@ -40,7 +40,6 @@ import org.springframework.web.context.request.NativeWebRequest;
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.5.2
|
||||
* @see org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter#setCustomArgumentResolvers
|
||||
* @see org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter#setCustomArgumentResolvers
|
||||
*/
|
||||
public interface WebArgumentResolver {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -65,12 +65,6 @@ public interface WebApplicationContext extends ApplicationContext {
|
||||
*/
|
||||
String SCOPE_SESSION = "session";
|
||||
|
||||
/**
|
||||
* Scope identifier for global session scope: "globalSession".
|
||||
* Supported in addition to the standard scopes "singleton" and "prototype".
|
||||
*/
|
||||
String SCOPE_GLOBAL_SESSION = "globalSession";
|
||||
|
||||
/**
|
||||
* Scope identifier for the global web application scope: "application".
|
||||
* Supported in addition to the standard scopes "singleton" and "prototype".
|
||||
|
||||
@@ -20,13 +20,11 @@ import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import javax.faces.context.ExternalContext;
|
||||
import javax.faces.context.FacesContext;
|
||||
import javax.portlet.PortletSession;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
@@ -52,9 +50,6 @@ import org.springframework.web.util.WebUtils;
|
||||
*/
|
||||
public class FacesRequestAttributes implements RequestAttributes {
|
||||
|
||||
private static final boolean portletApiPresent =
|
||||
ClassUtils.isPresent("javax.portlet.PortletSession", FacesRequestAttributes.class.getClassLoader());
|
||||
|
||||
/**
|
||||
* We'll create a lot of these objects, so we don't want a new logger every time.
|
||||
*/
|
||||
@@ -108,42 +103,22 @@ public class FacesRequestAttributes implements RequestAttributes {
|
||||
|
||||
@Override
|
||||
public Object getAttribute(String name, int scope) {
|
||||
if (scope == SCOPE_GLOBAL_SESSION && portletApiPresent) {
|
||||
return PortletSessionAccessor.getAttribute(name, getExternalContext());
|
||||
}
|
||||
else {
|
||||
return getAttributeMap(scope).get(name);
|
||||
}
|
||||
return getAttributeMap(scope).get(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAttribute(String name, Object value, int scope) {
|
||||
if (scope == SCOPE_GLOBAL_SESSION && portletApiPresent) {
|
||||
PortletSessionAccessor.setAttribute(name, value, getExternalContext());
|
||||
}
|
||||
else {
|
||||
getAttributeMap(scope).put(name, value);
|
||||
}
|
||||
getAttributeMap(scope).put(name, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAttribute(String name, int scope) {
|
||||
if (scope == SCOPE_GLOBAL_SESSION && portletApiPresent) {
|
||||
PortletSessionAccessor.removeAttribute(name, getExternalContext());
|
||||
}
|
||||
else {
|
||||
getAttributeMap(scope).remove(name);
|
||||
}
|
||||
getAttributeMap(scope).remove(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getAttributeNames(int scope) {
|
||||
if (scope == SCOPE_GLOBAL_SESSION && portletApiPresent) {
|
||||
return PortletSessionAccessor.getAttributeNames(getExternalContext());
|
||||
}
|
||||
else {
|
||||
return StringUtils.toStringArray(getAttributeMap(scope).keySet());
|
||||
}
|
||||
return StringUtils.toStringArray(getAttributeMap(scope).keySet());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -237,58 +212,4 @@ public class FacesRequestAttributes implements RequestAttributes {
|
||||
return mutex;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Inner class to avoid hard-coded Portlet API dependency.
|
||||
*/
|
||||
private static class PortletSessionAccessor {
|
||||
|
||||
public static Object getAttribute(String name, ExternalContext externalContext) {
|
||||
Object session = externalContext.getSession(false);
|
||||
if (session instanceof PortletSession) {
|
||||
return ((PortletSession) session).getAttribute(name, PortletSession.APPLICATION_SCOPE);
|
||||
}
|
||||
else if (session != null) {
|
||||
return externalContext.getSessionMap().get(name);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public static void setAttribute(String name, Object value, ExternalContext externalContext) {
|
||||
Object session = externalContext.getSession(true);
|
||||
if (session instanceof PortletSession) {
|
||||
((PortletSession) session).setAttribute(name, value, PortletSession.APPLICATION_SCOPE);
|
||||
}
|
||||
else {
|
||||
externalContext.getSessionMap().put(name, value);
|
||||
}
|
||||
}
|
||||
|
||||
public static void removeAttribute(String name, ExternalContext externalContext) {
|
||||
Object session = externalContext.getSession(false);
|
||||
if (session instanceof PortletSession) {
|
||||
((PortletSession) session).removeAttribute(name, PortletSession.APPLICATION_SCOPE);
|
||||
}
|
||||
else if (session != null) {
|
||||
externalContext.getSessionMap().remove(name);
|
||||
}
|
||||
}
|
||||
|
||||
public static String[] getAttributeNames(ExternalContext externalContext) {
|
||||
Object session = externalContext.getSession(false);
|
||||
if (session instanceof PortletSession) {
|
||||
return StringUtils.toStringArray(
|
||||
((PortletSession) session).getAttributeNames(PortletSession.APPLICATION_SCOPE));
|
||||
}
|
||||
else if (session != null) {
|
||||
return StringUtils.toStringArray(externalContext.getSessionMap().keySet());
|
||||
}
|
||||
else {
|
||||
return new String[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -155,11 +155,6 @@ public class FacesWebRequest extends FacesRequestAttributes implements NativeWeb
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Last-modified handling not supported for portlet requests:
|
||||
* As a consequence, this method always returns {@code false}.
|
||||
* @since 4.2
|
||||
*/
|
||||
@Override
|
||||
public boolean checkNotModified(String etag, long lastModifiedTimestamp) {
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,16 +31,12 @@ public interface NativeWebRequest extends WebRequest {
|
||||
/**
|
||||
* Return the underlying native request object, if available.
|
||||
* @see javax.servlet.http.HttpServletRequest
|
||||
* @see javax.portlet.ActionRequest
|
||||
* @see javax.portlet.RenderRequest
|
||||
*/
|
||||
Object getNativeRequest();
|
||||
|
||||
/**
|
||||
* Return the underlying native response object, if available.
|
||||
* @see javax.servlet.http.HttpServletResponse
|
||||
* @see javax.portlet.ActionResponse
|
||||
* @see javax.portlet.RenderResponse
|
||||
*/
|
||||
Object getNativeResponse();
|
||||
|
||||
@@ -50,8 +46,6 @@ public interface NativeWebRequest extends WebRequest {
|
||||
* @return the matching request object, or {@code null} if none
|
||||
* of that type is available
|
||||
* @see javax.servlet.http.HttpServletRequest
|
||||
* @see javax.portlet.ActionRequest
|
||||
* @see javax.portlet.RenderRequest
|
||||
*/
|
||||
<T> T getNativeRequest(Class<T> requiredType);
|
||||
|
||||
@@ -61,8 +55,6 @@ public interface NativeWebRequest extends WebRequest {
|
||||
* @return the matching response object, or {@code null} if none
|
||||
* of that type is available
|
||||
* @see javax.servlet.http.HttpServletResponse
|
||||
* @see javax.portlet.ActionResponse
|
||||
* @see javax.portlet.RenderResponse
|
||||
*/
|
||||
<T> T getNativeResponse(Class<T> requiredType);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -22,12 +22,11 @@ package org.springframework.web.context.request;
|
||||
* attributes, with the optional notion of a "global session".
|
||||
*
|
||||
* <p>Can be implemented for any kind of request/session mechanism,
|
||||
* in particular for servlet requests and portlet requests.
|
||||
* in particular for servlet requests.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see ServletRequestAttributes
|
||||
* @see org.springframework.web.portlet.context.PortletRequestAttributes
|
||||
*/
|
||||
public interface RequestAttributes {
|
||||
|
||||
@@ -44,14 +43,6 @@ public interface RequestAttributes {
|
||||
*/
|
||||
int SCOPE_SESSION = 1;
|
||||
|
||||
/**
|
||||
* Constant that indicates global session scope.
|
||||
* <p>This explicitly refers to a globally shared session, if such
|
||||
* a distinction is available (for example, in a Portlet environment).
|
||||
* Else, it simply refers to the common session.
|
||||
*/
|
||||
int SCOPE_GLOBAL_SESSION = 2;
|
||||
|
||||
|
||||
/**
|
||||
* Name of the standard reference to the request object: "request".
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -31,9 +31,8 @@ import org.springframework.util.ClassUtils;
|
||||
* <p>Use {@link RequestContextListener} or
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} to expose
|
||||
* the current web request. Note that
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet} and
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet} already
|
||||
* expose the current request by default.
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}
|
||||
* already exposes the current request by default.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Rod Johnson
|
||||
@@ -41,7 +40,6 @@ import org.springframework.util.ClassUtils;
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public abstract class RequestContextHolder {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -25,11 +25,6 @@ package org.springframework.web.context.request;
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} or
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
*
|
||||
* <p>This {@code Scope} will also work for Portlet environments,
|
||||
* through an alternate {@code RequestAttributes} implementation
|
||||
* (as exposed out-of-the-box by Spring's
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
@@ -39,7 +34,6 @@ package org.springframework.web.context.request;
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public class RequestScope extends AbstractRequestAttributesScope {
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -27,58 +27,21 @@ import org.springframework.beans.factory.ObjectFactory;
|
||||
* {@link org.springframework.web.filter.RequestContextFilter} or
|
||||
* {@link org.springframework.web.servlet.DispatcherServlet}.
|
||||
*
|
||||
* <p>This {@code Scope} will also work for Portlet environments,
|
||||
* through an alternate {@code RequestAttributes} implementation
|
||||
* (as exposed out-of-the-box by Spring's
|
||||
* {@link org.springframework.web.portlet.DispatcherPortlet}.
|
||||
*
|
||||
* @author Rod Johnson
|
||||
* @author Juergen Hoeller
|
||||
* @author Rob Harrop
|
||||
* @since 2.0
|
||||
* @see RequestContextHolder#currentRequestAttributes()
|
||||
* @see RequestAttributes#SCOPE_SESSION
|
||||
* @see RequestAttributes#SCOPE_GLOBAL_SESSION
|
||||
* @see RequestContextListener
|
||||
* @see org.springframework.web.filter.RequestContextFilter
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
*/
|
||||
public class SessionScope extends AbstractRequestAttributesScope {
|
||||
|
||||
private final int scope;
|
||||
|
||||
|
||||
/**
|
||||
* Create a new SessionScope, storing attributes in a locally
|
||||
* isolated session (or default session, if there is no distinction
|
||||
* between a global session and a component-specific session).
|
||||
*/
|
||||
public SessionScope() {
|
||||
this.scope = RequestAttributes.SCOPE_SESSION;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new SessionScope, specifying whether to store attributes
|
||||
* in the global session, provided that such a distinction is available.
|
||||
* <p>This distinction is important for Portlet environments, where there
|
||||
* are two notions of a session: "portlet scope" and "application scope".
|
||||
* If this flag is on, objects will be put into the "application scope" session;
|
||||
* else they will end up in the "portlet scope" session (the typical default).
|
||||
* <p>In a Servlet environment, this flag is effectively ignored.
|
||||
* @param globalSession {@code true} in case of the global session as target;
|
||||
* {@code false} in case of a component-specific session as target
|
||||
* @see org.springframework.web.portlet.context.PortletRequestAttributes
|
||||
* @see ServletRequestAttributes
|
||||
*/
|
||||
public SessionScope(boolean globalSession) {
|
||||
this.scope = (globalSession ? RequestAttributes.SCOPE_GLOBAL_SESSION : RequestAttributes.SCOPE_SESSION);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected int getScope() {
|
||||
return this.scope;
|
||||
return RequestAttributes.SCOPE_SESSION;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -52,11 +52,6 @@ import org.springframework.ui.ModelMap;
|
||||
* @see org.springframework.web.servlet.DispatcherServlet
|
||||
* @see org.springframework.web.servlet.handler.AbstractHandlerMapping#setInterceptors
|
||||
* @see org.springframework.web.servlet.HandlerInterceptor
|
||||
* @see org.springframework.web.portlet.context.PortletWebRequest
|
||||
* @see org.springframework.web.portlet.DispatcherPortlet
|
||||
* @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setInterceptors
|
||||
* @see org.springframework.web.portlet.handler.AbstractHandlerMapping#setApplyWebRequestInterceptorsToRenderPhaseOnly
|
||||
* @see org.springframework.web.portlet.HandlerInterceptor
|
||||
*/
|
||||
public interface WebRequestInterceptor {
|
||||
|
||||
|
||||
@@ -177,8 +177,7 @@ public abstract class WebApplicationContextUtils {
|
||||
*/
|
||||
public static void registerWebApplicationScopes(ConfigurableListableBeanFactory beanFactory, ServletContext sc) {
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_REQUEST, new RequestScope());
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope(false));
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_GLOBAL_SESSION, new SessionScope(true));
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_SESSION, new SessionScope());
|
||||
if (sc != null) {
|
||||
ServletContextScope appScope = new ServletContextScope(sc);
|
||||
beanFactory.registerScope(WebApplicationContext.SCOPE_APPLICATION, appScope);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2012 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -23,10 +23,8 @@ import java.util.Map;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
/**
|
||||
* This interface defines the multipart request access operations
|
||||
* that are exposed for actual multipart requests. It is extended
|
||||
* by {@link MultipartHttpServletRequest} and the Portlet
|
||||
* {@link org.springframework.web.portlet.multipart.MultipartActionRequest}.
|
||||
* This interface defines the multipart request access operations that are exposed
|
||||
* for actual multipart requests. It is extended by {@link MultipartHttpServletRequest}.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @author Arjen Poutsma
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
* Copyright 2002-2016 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@@ -47,16 +47,10 @@ import org.springframework.web.util.WebUtils;
|
||||
* as representation of uploaded files and a String-based parameter Map as
|
||||
* representation of uploaded form fields.
|
||||
*
|
||||
* <p>Subclasses implement concrete resolution strategies for Servlet or Portlet
|
||||
* environments: see CommonsMultipartResolver and CommonsPortletMultipartResolver,
|
||||
* respectively. This base class is not tied to either of those APIs, factoring
|
||||
* out common functionality.
|
||||
*
|
||||
* @author Juergen Hoeller
|
||||
* @since 2.0
|
||||
* @see CommonsMultipartFile
|
||||
* @see CommonsMultipartResolver
|
||||
* @see org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver
|
||||
*/
|
||||
public abstract class CommonsFileUploadSupport {
|
||||
|
||||
|
||||
@@ -55,7 +55,6 @@ import org.springframework.web.util.WebUtils;
|
||||
* @since 29.09.2003
|
||||
* @see #CommonsMultipartResolver(ServletContext)
|
||||
* @see #setResolveLazily
|
||||
* @see org.springframework.web.portlet.multipart.CommonsPortletMultipartResolver
|
||||
* @see org.apache.commons.fileupload.servlet.ServletFileUpload
|
||||
* @see org.apache.commons.fileupload.disk.DiskFileItemFactory
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user