SPR-6464 Add @FlashAttributes annotation and FlashStatus method argument
This commit is contained in:
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2002-2010 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;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* Annotation that indicates what attributes should be stored in the session or in
|
||||
* some conversational storage in order to survive a client-side redirect.
|
||||
*
|
||||
* TODO ...
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*
|
||||
* @see org.springframework.web.bind.support.FlashStatus
|
||||
*/
|
||||
@Target({ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Inherited
|
||||
@Documented
|
||||
public @interface FlashAttributes {
|
||||
|
||||
/**
|
||||
* The names of flash attributes in the model to be stored.
|
||||
*
|
||||
* TODO ...
|
||||
*/
|
||||
String[] value() default {};
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*
|
||||
*/
|
||||
Class[] types() default {};
|
||||
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.support;
|
||||
|
||||
import org.springframework.web.bind.annotation.FlashAttributes;
|
||||
|
||||
|
||||
/**
|
||||
* Simple interface to pass into controller methods to allow them to activate
|
||||
* a mode in which model attributes identified as "flash attributes" are
|
||||
* temporarily stored in the session to make them available to the next
|
||||
* request. The most common scenario is a client-side redirect.
|
||||
*
|
||||
* <p>In active mode, model attributes that match the attribute names or
|
||||
* types declared via @{@link FlashAttributes} are saved in the session.
|
||||
* On the next request, any flash attributes found in the session are
|
||||
* automatically added to the model of the target controller method and
|
||||
* are also cleared from the session.
|
||||
*
|
||||
* TODO ...
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public interface FlashStatus {
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
void setActive();
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
boolean isActive();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.support;
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class SimpleFlashStatus implements FlashStatus {
|
||||
|
||||
private boolean active = false;
|
||||
|
||||
public void setActive() {
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
public boolean isActive() {
|
||||
return this.active;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
/*
|
||||
* Copyright 2002-2011 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.method.annotation;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.web.bind.annotation.FlashAttributes;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Manages flash attributes declared via @{@link FlashAttributes}.
|
||||
*
|
||||
* TODO ...
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
*/
|
||||
public class FlashAttributesHandler {
|
||||
|
||||
public static final String FLASH_ATTRIBUTES_SESSION_KEY = FlashAttributesHandler.class.getName() + ".attributes";
|
||||
|
||||
private final Set<String> attributeNames = new HashSet<String>();
|
||||
|
||||
private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>();
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
public FlashAttributesHandler(Class<?> handlerType) {
|
||||
FlashAttributes annotation = AnnotationUtils.findAnnotation(handlerType, FlashAttributes.class);
|
||||
if (annotation != null) {
|
||||
this.attributeNames.addAll(Arrays.asList(annotation.value()));
|
||||
this.attributeTypes.addAll(Arrays.<Class<?>>asList(annotation.types()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether the controller represented by this handler has declared flash
|
||||
* attribute names or types via @{@link FlashAttributes}.
|
||||
*/
|
||||
public boolean hasFlashAttributes() {
|
||||
return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
public boolean isFlashAttribute(String attributeName, Class<?> attributeType) {
|
||||
return (this.attributeNames.contains(attributeName) || this.attributeTypes.contains(attributeType));
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
public void storeAttributes(WebRequest request, Map<String, ?> attributes) {
|
||||
Map<String, Object> filtered = filterAttributes(attributes);
|
||||
if (!filtered.isEmpty()) {
|
||||
request.setAttribute(FLASH_ATTRIBUTES_SESSION_KEY, filtered, WebRequest.SCOPE_SESSION);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> filterAttributes(Map<String, ?> attributes) {
|
||||
Map<String, Object> result = new LinkedHashMap<String, Object>();
|
||||
for (String name : attributes.keySet()) {
|
||||
Object value = attributes.get(name);
|
||||
Class<?> type = (value != null) ? value.getClass() : null;
|
||||
if (isFlashAttribute(name, type)) {
|
||||
result.put(name, value);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map<String, Object> retrieveAttributes(WebRequest request) {
|
||||
return (Map<String, Object>) request.getAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO ...
|
||||
*/
|
||||
public void cleanupAttributes(WebRequest request) {
|
||||
request.removeAttribute(FLASH_ATTRIBUTES_SESSION_KEY, WebRequest.SCOPE_SESSION);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.core.Conventions;
|
||||
import org.springframework.core.GenericTypeResolver;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.ui.Model;
|
||||
import org.springframework.ui.ModelMap;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.validation.BindingResult;
|
||||
@@ -34,6 +35,7 @@ import org.springframework.web.bind.WebDataBinder;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.SessionAttributes;
|
||||
import org.springframework.web.bind.support.FlashStatus;
|
||||
import org.springframework.web.bind.support.SessionStatus;
|
||||
import org.springframework.web.bind.support.WebDataBinderFactory;
|
||||
import org.springframework.web.context.request.NativeWebRequest;
|
||||
@@ -42,15 +44,16 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
|
||||
import org.springframework.web.method.support.ModelAndViewContainer;
|
||||
|
||||
/**
|
||||
* Contains methods for creating and updating a model. A {@link ModelFactory} is associated with a specific controller
|
||||
* through knowledge of its @{@link ModelAttribute} methods and @{@link SessionAttributes}.
|
||||
* Provides methods to initialize the {@link Model} before a controller method
|
||||
* invocation and to update it after the controller method has been invoked.
|
||||
*
|
||||
* <p>{@link #initModel(NativeWebRequest, ModelAndViewContainer, HandlerMethod)} populates the model
|
||||
* with handler session attributes and by invoking model attribute methods.
|
||||
* <p>On initialization the model may be populated with session attributes
|
||||
* stored during a previous request as a result of a {@link SessionAttributes}
|
||||
* annotation. @{@link ModelAttribute} methods in the same controller may
|
||||
* also be invoked to populate the model.
|
||||
*
|
||||
* <p>{@link #updateModel(NativeWebRequest, ModelAndViewContainer, SessionStatus)} updates
|
||||
* the model (usually after the {@link RequestMapping} method has been called) promoting attributes
|
||||
* to the session and adding {@link BindingResult} attributes as necessary.
|
||||
* <p>On update attributes may be removed from or stored in the session.
|
||||
* {@link BindingResult} attributes may also be added as necessary.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -61,45 +64,52 @@ public final class ModelFactory {
|
||||
|
||||
private final WebDataBinderFactory binderFactory;
|
||||
|
||||
private final SessionAttributesHandler sessionHandler;
|
||||
private final SessionAttributesHandler sessionAttributesHandler;
|
||||
|
||||
private final FlashAttributesHandler flashAttributesHandler;
|
||||
|
||||
/**
|
||||
* Create a ModelFactory instance with the provided {@link ModelAttribute} methods.
|
||||
* @param attributeMethods {@link ModelAttribute}-annotated methods to invoke when populating a model
|
||||
* @param binderFactory the binder factory to use when adding {@link BindingResult}s to the model
|
||||
* @param sessionHandler a session attributes handler to synch attributes with the session
|
||||
* @param attributeMethods {@link ModelAttribute} methods to initialize model instances with
|
||||
* @param binderFactory used to add {@link BindingResult} attributes to the model
|
||||
* @param sessionAttributesHandler used to access handler-specific session attributes
|
||||
* @param flashAttributesHandler used to access flash attributes
|
||||
*/
|
||||
public ModelFactory(List<InvocableHandlerMethod> attributeMethods,
|
||||
WebDataBinderFactory binderFactory,
|
||||
SessionAttributesHandler sessionHandler) {
|
||||
SessionAttributesHandler sessionAttributesHandler,
|
||||
FlashAttributesHandler flashAttributesHandler) {
|
||||
this.attributeMethods = (attributeMethods != null) ? attributeMethods : new ArrayList<InvocableHandlerMethod>();
|
||||
this.binderFactory = binderFactory;
|
||||
this.sessionHandler = sessionHandler;
|
||||
this.sessionAttributesHandler = sessionAttributesHandler;
|
||||
this.flashAttributesHandler = flashAttributesHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Populate the model for a request with attributes obtained in the following order:
|
||||
* Populate the model in the following order:
|
||||
* <ol>
|
||||
* <li>Retrieve "known" (i.e. have been in the model in prior requests) handler session attributes from the session
|
||||
* <li>Create attributes by invoking model attribute methods
|
||||
* <li>Check for not yet known handler session attributes in the session
|
||||
* <li>Retrieve "remembered" (i.e. previously stored) controller-specific session attributes
|
||||
* <li>Invoke @{@link ModelAttribute} methods
|
||||
* <li>Check the session for any controller-specific attributes not yet "remembered".
|
||||
* </ol>
|
||||
* <p>As a general rule model attributes are added only once following the above order.
|
||||
*
|
||||
* @param request the current request
|
||||
* @param mavContainer the {@link ModelAndViewContainer} to add model attributes to
|
||||
* @param requestMethod the request handling method for which the model is needed
|
||||
* @throws Exception if an exception occurs while invoking model attribute methods
|
||||
* @param mavContainer contains the model to initialize
|
||||
* @param handlerMethod the @{@link RequestMapping} method for which the model is initialized
|
||||
* @throws Exception may arise from the invocation of @{@link ModelAttribute} methods
|
||||
*/
|
||||
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod requestMethod)
|
||||
public void initModel(NativeWebRequest request, ModelAndViewContainer mavContainer, HandlerMethod handlerMethod)
|
||||
throws Exception {
|
||||
|
||||
Map<String, ?> sessionAttributes = this.sessionHandler.retrieveHandlerSessionAttributes(request);
|
||||
mavContainer.addAllAttributes(sessionAttributes);
|
||||
Map<String, ?> sessionAttrs = this.sessionAttributesHandler.retrieveAttributes(request);
|
||||
mavContainer.addAllAttributes(sessionAttrs);
|
||||
|
||||
Map<String, ?> flashAttrs = this.flashAttributesHandler.retrieveAttributes(request);
|
||||
mavContainer.addAllAttributes(flashAttrs);
|
||||
this.flashAttributesHandler.cleanupAttributes(request);
|
||||
|
||||
invokeAttributeMethods(request, mavContainer);
|
||||
|
||||
checkMissingSessionAttributes(request, mavContainer, requestMethod);
|
||||
checkHandlerSessionAttributes(request, mavContainer, handlerMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,26 +135,26 @@ public final class ModelFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if any {@link ModelAttribute}-annotated handler method arguments are eligible as handler session
|
||||
* attributes, as defined by @{@link SessionAttributes}, and are not yet present in the model.
|
||||
* If so, attempts to retrieve them from the session and add them to the model.
|
||||
* Checks if any @{@link ModelAttribute} handler method arguments declared as
|
||||
* session attributes via @{@link SessionAttributes} but are not already in the
|
||||
* model. If found add them to the model, raise an exception otherwise.
|
||||
*
|
||||
* @throws HttpSessionRequiredException raised if a handler session attribute could is missing
|
||||
*/
|
||||
private void checkMissingSessionAttributes(NativeWebRequest request,
|
||||
private void checkHandlerSessionAttributes(NativeWebRequest request,
|
||||
ModelAndViewContainer mavContainer,
|
||||
HandlerMethod requestMethod) throws HttpSessionRequiredException {
|
||||
for (MethodParameter parameter : requestMethod.getMethodParameters()) {
|
||||
HandlerMethod handlerMethod) throws HttpSessionRequiredException {
|
||||
for (MethodParameter parameter : handlerMethod.getMethodParameters()) {
|
||||
if (parameter.hasParameterAnnotation(ModelAttribute.class)) {
|
||||
String name = getNameForParameter(parameter);
|
||||
if (!mavContainer.containsAttribute(name)) {
|
||||
if (sessionHandler.isHandlerSessionAttribute(name, parameter.getParameterType())) {
|
||||
Object attrValue = sessionHandler.retrieveAttribute(request, name);
|
||||
String attrName = getNameForParameter(parameter);
|
||||
if (!mavContainer.containsAttribute(attrName)) {
|
||||
if (sessionAttributesHandler.isHandlerSessionAttribute(attrName, parameter.getParameterType())) {
|
||||
Object attrValue = sessionAttributesHandler.retrieveAttribute(request, attrName);
|
||||
if (attrValue == null){
|
||||
throw new HttpSessionRequiredException(
|
||||
"Session attribute '" + name + "' not found in session: " + requestMethod);
|
||||
"Session attribute '" + attrName + "' not found in session: " + handlerMethod);
|
||||
}
|
||||
mavContainer.addAttribute(name, attrValue);
|
||||
mavContainer.addAttribute(attrName, attrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -196,15 +206,20 @@ public final class ModelFactory {
|
||||
* @param sessionStatus whether session processing is complete
|
||||
* @throws Exception if the process of creating {@link BindingResult} attributes causes an error
|
||||
*/
|
||||
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer, SessionStatus sessionStatus)
|
||||
throws Exception {
|
||||
public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer,
|
||||
SessionStatus sessionStatus, FlashStatus flashStatus) throws Exception {
|
||||
|
||||
if (sessionStatus.isComplete()){
|
||||
this.sessionHandler.cleanupHandlerSessionAttributes(request);
|
||||
this.sessionAttributesHandler.cleanupAttributes(request);
|
||||
}
|
||||
else {
|
||||
this.sessionAttributesHandler.storeAttributes(request, mavContainer.getModel());
|
||||
}
|
||||
|
||||
this.sessionHandler.storeHandlerSessionAttributes(request, mavContainer.getModel());
|
||||
|
||||
if (flashStatus.isActive()) {
|
||||
this.flashAttributesHandler.storeAttributes(request, mavContainer.getModel());
|
||||
}
|
||||
|
||||
if (mavContainer.isResolveView()) {
|
||||
updateBindingResult(request, mavContainer.getModel());
|
||||
}
|
||||
@@ -238,7 +253,7 @@ public final class ModelFactory {
|
||||
}
|
||||
|
||||
Class<?> attrType = (value != null) ? value.getClass() : null;
|
||||
if (this.sessionHandler.isHandlerSessionAttribute(attributeName, attrType)) {
|
||||
if (this.sessionAttributesHandler.isHandlerSessionAttribute(attributeName, attrType)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -32,22 +32,15 @@ import org.springframework.web.bind.support.SessionStatus;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
|
||||
/**
|
||||
* Provides operations for managing handler-specific session attributes as defined by the
|
||||
* {@link SessionAttributes} type-level annotation performing all operations through an
|
||||
* instance of a {@link SessionAttributeStore}.
|
||||
* Manages handler-specific session attributes declared via @{@link SessionAttributes}.
|
||||
* Actual storage is performed through an instance of {@link SessionAttributeStore}.
|
||||
*
|
||||
* <p>A typical scenario involves a handler adding attributes to the {@link Model} during
|
||||
* a request. At the end of the request, model attributes that match to session attribute
|
||||
* names defined through an {@link SessionAttributes} annotation are automatically
|
||||
* "promoted" to the session. Handler session attributes are then removed when
|
||||
* {@link SessionStatus#setComplete()} is called by a handler.
|
||||
*
|
||||
* <p>Therefore "session attributes" for this class means only attributes that have been
|
||||
* previously confirmed by calls to {@link #isHandlerSessionAttribute(String, Class)}.
|
||||
* Attribute names that have never been resolved that way will be filtered out from
|
||||
* operations of this class. That means initially the actual set of resolved session
|
||||
* attribute names is empty and it grows gradually as attributes are added to
|
||||
* the {@link Model} and then considered for being added to the session.
|
||||
* <p>A typical scenario begins with a controller adding attributes to the {@link Model}.
|
||||
* At the end of the request, model attributes are checked to see if any of them match
|
||||
* the names and types declared via @{@link SessionAttributes}. Matching model
|
||||
* attributes are "promoted" to the session and remain there until the controller
|
||||
* calls {@link SessionStatus#setComplete()} to indicate the session attributes are
|
||||
* no longer needed and can be removed.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 3.1
|
||||
@@ -56,48 +49,48 @@ public class SessionAttributesHandler {
|
||||
|
||||
private final Set<String> attributeNames = new HashSet<String>();
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
private final Set<Class> attributeTypes = new HashSet<Class>();
|
||||
private final Set<Class<?>> attributeTypes = new HashSet<Class<?>>();
|
||||
|
||||
private final Set<String> resolvedAttributeNames = Collections.synchronizedSet(new HashSet<String>(4));
|
||||
|
||||
private final SessionAttributeStore attributeStore;
|
||||
private final SessionAttributeStore sessionAttributeStore;
|
||||
|
||||
/**
|
||||
* Creates a {@link SessionAttributesHandler} instance for the specified handlerType.
|
||||
* <p>Inspects the given handler type for the presence of a {@link SessionAttributes} annotation and
|
||||
* stores that information for use in subsequent calls to {@link #isHandlerSessionAttribute(String, Class)}.
|
||||
* If the handler type does not contain such an annotation,
|
||||
* {@link #isHandlerSessionAttribute(String, Class)} always returns {@code false} and all other operations
|
||||
* on handler session attributes have no effect on the backend session.
|
||||
* <p>Use {@link #hasSessionAttributes()} to check if the handler type has defined any session attribute names
|
||||
* of interest through a {@link SessionAttributes} annotation.
|
||||
* Creates a {@link SessionAttributesHandler} instance for the specified handler type
|
||||
* Inspects the given handler type for the presence of an @{@link SessionAttributes}
|
||||
* and stores that information to identify model attribute that need to be stored,
|
||||
* retrieved, or removed from the session.
|
||||
* @param handlerType the handler type to inspect for a {@link SessionAttributes} annotation
|
||||
* @param attributeStore the {@link SessionAttributeStore} to delegate to for the actual backend session access
|
||||
* @param sessionAttributeStore used for session access
|
||||
*/
|
||||
public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore attributeStore) {
|
||||
Assert.notNull(attributeStore, "SessionAttributeStore may not be null.");
|
||||
this.attributeStore = attributeStore;
|
||||
public SessionAttributesHandler(Class<?> handlerType, SessionAttributeStore sessionAttributeStore) {
|
||||
Assert.notNull(sessionAttributeStore, "SessionAttributeStore may not be null.");
|
||||
this.sessionAttributeStore = sessionAttributeStore;
|
||||
|
||||
SessionAttributes annotation = AnnotationUtils.findAnnotation(handlerType, SessionAttributes.class);
|
||||
if (annotation != null) {
|
||||
this.attributeNames.addAll(Arrays.asList(annotation.value()));
|
||||
this.attributeTypes.addAll(Arrays.asList(annotation.types()));
|
||||
this.attributeTypes.addAll(Arrays.<Class<?>>asList(annotation.types()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the handler type has specified any session attribute names of interest through a
|
||||
* {@link SessionAttributes} annotation.
|
||||
* Whether the controller represented by this handler has declared session
|
||||
* attribute names or types of interest via @{@link SessionAttributes}.
|
||||
*/
|
||||
public boolean hasSessionAttributes() {
|
||||
return ((this.attributeNames.size() > 0) || (this.attributeTypes.size() > 0));
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether or not an attribute is a handler session attribute of interest as defined
|
||||
* in a {@link SessionAttributes} annotation. Attributes names successfully resolved through
|
||||
* this method are remembered and in other operations.
|
||||
* Whether the controller represented by this instance has declared a specific
|
||||
* attribute as a session attribute via @{@link SessionAttributes}.
|
||||
*
|
||||
* <p>Attributes successfully resolved through this method are "remembered" and
|
||||
* used by calls to {@link #retrieveAttributes(WebRequest)} and
|
||||
* {@link #cleanupAttributes(WebRequest)}. In other words unless attributes
|
||||
* have been resolved and stored before, retrieval and cleanup have no impact.
|
||||
*
|
||||
* @param attributeName the attribute name to check, must not be null
|
||||
* @param attributeType the type for the attribute, not required but should be provided when
|
||||
* available as session attributes of interest can be matched by type
|
||||
@@ -114,29 +107,32 @@ public class SessionAttributesHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the specified attribute through the underlying {@link SessionAttributeStore}.
|
||||
* Although not required use of this method implies a prior call to
|
||||
* {@link #isHandlerSessionAttribute(String, Class)} has been made to see if the attribute
|
||||
* name is a handler-specific session attribute of interest.
|
||||
* @param request the request for the session operation
|
||||
* @param attributeName the name of the attribute
|
||||
* @return the attribute value or {@code null} if none
|
||||
* Stores a subset of the given attributes in the session. Attributes not
|
||||
* declared as session attributes via @{@link SessionAttributes} are ignored.
|
||||
* @param request the current request
|
||||
* @param attributes candidate attributes for session storage
|
||||
*/
|
||||
public Object retrieveAttribute(WebRequest request, String attributeName) {
|
||||
return this.attributeStore.retrieveAttribute(request, attributeName);
|
||||
public void storeAttributes(WebRequest request, Map<String, ?> attributes) {
|
||||
for (String name : attributes.keySet()) {
|
||||
Object value = attributes.get(name);
|
||||
Class<?> attrType = (value != null) ? value.getClass() : null;
|
||||
|
||||
if (isHandlerSessionAttribute(name, attrType)) {
|
||||
this.sessionAttributeStore.storeAttribute(request, name, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve attributes for the underlying handler type from the backend session.
|
||||
* <p>Only attributes that have previously been successfully resolved via calls to
|
||||
* {@link #isHandlerSessionAttribute(String, Class)} are considered.
|
||||
* Retrieves "remembered" (i.e. previously stored) session attributes
|
||||
* for the controller represented by this handler.
|
||||
* @param request the current request
|
||||
* @return a map with attributes or an empty map
|
||||
* @return a map with handler session attributes; possibly empty.
|
||||
*/
|
||||
public Map<String, ?> retrieveHandlerSessionAttributes(WebRequest request) {
|
||||
public Map<String, Object> retrieveAttributes(WebRequest request) {
|
||||
Map<String, Object> attributes = new HashMap<String, Object>();
|
||||
for (String name : this.resolvedAttributeNames) {
|
||||
Object value = this.attributeStore.retrieveAttribute(request, name);
|
||||
Object value = this.sessionAttributeStore.retrieveAttribute(request, name);
|
||||
if (value != null) {
|
||||
attributes.put(name, value);
|
||||
}
|
||||
@@ -145,34 +141,24 @@ public class SessionAttributesHandler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean up attributes for the underlying handler type from the backend session.
|
||||
* <p>Only attributes that have previously been successfully resolved via calls to
|
||||
* {@link #isHandlerSessionAttribute(String, Class)} are removed.
|
||||
* Cleans "remembered" (i.e. previously stored) session attributes
|
||||
* for the controller represented by this handler.
|
||||
* @param request the current request
|
||||
*/
|
||||
public void cleanupHandlerSessionAttributes(WebRequest request) {
|
||||
public void cleanupAttributes(WebRequest request) {
|
||||
for (String attributeName : this.resolvedAttributeNames) {
|
||||
this.attributeStore.cleanupAttribute(request, attributeName);
|
||||
this.sessionAttributeStore.cleanupAttribute(request, attributeName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store attributes in the backend session.
|
||||
* <p>Only attributes that have previously been successfully resolved via calls to
|
||||
* {@link #isHandlerSessionAttribute(String, Class)} are stored. All other attributes
|
||||
* from the input map are ignored.
|
||||
* A pass-through call to the underlying {@link SessionAttributeStore}.
|
||||
* @param request the current request
|
||||
* @param attributes the attribute pairs to consider for storing
|
||||
* @param attributeName the name of the attribute of interest
|
||||
* @return the attribute value or {@code null}
|
||||
*/
|
||||
public void storeHandlerSessionAttributes(WebRequest request, Map<String, Object> attributes) {
|
||||
for (String name : attributes.keySet()) {
|
||||
Object value = attributes.get(name);
|
||||
Class<?> attrType = (value != null) ? value.getClass() : null;
|
||||
|
||||
if (isHandlerSessionAttribute(name, attrType)) {
|
||||
this.attributeStore.storeAttribute(request, name, value);
|
||||
}
|
||||
}
|
||||
Object retrieveAttribute(WebRequest request, String attributeName) {
|
||||
return this.sessionAttributeStore.retrieveAttribute(request, attributeName);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user