@ -1,5 +1,5 @@
@@ -1,5 +1,5 @@
/ *
* Copyright 2002 - 2014 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 .
@ -45,14 +45,14 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
@@ -45,14 +45,14 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer ;
/ * *
* Provides methods to initialize the { @link Model } before controller method
* invocation and to update it afterwards .
* Assist with initialization of the { @link Model } before controller method
* invocation and with updates to it after the invocation .
*
* < p > On initialization , the model is populated with attributes from the session
* and by invoking methods annotated with { @code @ModelAttribute } .
* < p > On initialization the model is populated with attributes temporarily stored
* in the session and through the invocation of { @code @ModelAttribute } methods .
*
* < p > On update , model attributes are synchronized with the session and also
* { @link BindingResult } attributes are added where missing .
* < p > On update model attributes are synchronized with the session and also
* { @link BindingResult } attributes are added if missing .
*
* @author Rossen Stoyanchev
* @since 3 . 1
@ -70,51 +70,51 @@ public final class ModelFactory {
@@ -70,51 +70,51 @@ public final class ModelFactory {
/ * *
* Create a new instance with the given { @code @ModelAttribute } methods .
* @param invocable Methods the { @code @ModelAttribute } methods to invoke
* @param dataB inderFactory for preparation of { @link BindingResult } attributes
* @param sessionAttributes Handler for access to session attributes
* @param handler Methods the { @code @ModelAttribute } methods to invoke
* @param b inderFactory for preparation of { @link BindingResult } attributes
* @param attribute Handler for access to session attributes
* /
public ModelFactory ( List < InvocableHandlerMethod > invocableMethods , WebDataBinderFactory dataBinderFactory ,
SessionAttributesHandler sessionAttributes Handler) {
public ModelFactory ( List < InvocableHandlerMethod > handlerMethods ,
WebDataBinderFactory binderFactory , SessionAttributesHandler attribute Handler) {
if ( invocable Methods ! = null ) {
for ( InvocableHandlerMethod method : invocable Methods) {
this . modelMethods . add ( new ModelMethod ( m ethod) ) ;
if ( handler Methods ! = null ) {
for ( InvocableHandlerMethod handlerMethod : handler Methods) {
this . modelMethods . add ( new ModelMethod ( handlerM ethod) ) ;
}
}
this . dataBinderFactory = dataB inderFactory;
this . sessionAttributesHandler = sessionAttributes Handler;
this . dataBinderFactory = b inderFactory;
this . sessionAttributesHandler = attribute Handler;
}
/ * *
* Populate the model in the following order :
* < ol >
* < li > Retrieve "known" session attributes listed as { @code @SessionAttributes } .
* < li > Invoke { @code @ModelAttribute } methods
* < li > Find { @code @ModelAttribute } method arguments also listed as
* { @code @SessionAttributes } and ensure they ' re present in the model raising
* an exception if necessary .
* < li > Retrieve "known" session attributes listed as { @code @SessionAttributes } .
* < li > Invoke { @code @ModelAttribute } methods
* < li > Find { @code @ModelAttribute } method arguments also listed as
* { @code @SessionAttributes } and ensure they ' re present in the model raising
* an exception if necessary .
* < / ol >
* @param request the current request
* @param mavC ontainer a container with the model to be initialized
* @param c ontainer a container with the model to be initialized
* @param handlerMethod the method for which the model is initialized
* @throws Exception may arise from { @code @ModelAttribute } methods
* /
public void initModel ( NativeWebRequest request , ModelAndViewContainer mavContainer , HandlerMethod handlerMethod )
throws Exception {
public void initModel ( NativeWebRequest request , ModelAndViewContainer container ,
HandlerMethod handlerMethod ) throws Exception {
Map < String , ? > sessionAttributes = this . sessionAttributesHandler . retrieveAttributes ( request ) ;
mavContainer . mergeAttributes ( sessionAttributes ) ;
invokeModelAttributeMethods ( request , mavContainer ) ;
container . mergeAttributes ( sessionAttributes ) ;
invokeModelAttributeMethods ( request , container ) ;
for ( String name : findSessionAttributeArguments ( handlerMethod ) ) {
if ( ! mavC ontainer. containsAttribute ( name ) ) {
if ( ! c ontainer. containsAttribute ( name ) ) {
Object value = this . sessionAttributesHandler . retrieveAttribute ( request , name ) ;
if ( value = = null ) {
throw new HttpSessionRequiredException ( "Expected session attribute '" + name + "'" ) ;
}
mavC ontainer. addAttribute ( name , value ) ;
c ontainer. addAttribute ( name , value ) ;
}
}
}
@ -123,30 +123,29 @@ public final class ModelFactory {
@@ -123,30 +123,29 @@ public final class ModelFactory {
* Invoke model attribute methods to populate the model .
* Attributes are added only if not already present in the model .
* /
private void invokeModelAttributeMethods ( NativeWebRequest request , ModelAndViewContainer mavC ontainer)
private void invokeModelAttributeMethods ( NativeWebRequest request , ModelAndViewContainer c ontainer)
throws Exception {
while ( ! this . modelMethods . isEmpty ( ) ) {
InvocableHandlerMethod attr Method = getNextModelMethod ( mavC ontainer) . getHandlerMethod ( ) ;
String modelName = attr Method. getMethodAnnotation ( ModelAttribute . class ) . value ( ) ;
if ( mavC ontainer. containsAttribute ( modelName ) ) {
InvocableHandlerMethod model Method = getNextModelMethod ( c ontainer) . getHandlerMethod ( ) ;
String modelName = model Method. getMethodAnnotation ( ModelAttribute . class ) . value ( ) ;
if ( c ontainer. containsAttribute ( modelName ) ) {
continue ;
}
Object returnValue = attrMethod . invokeForRequest ( request , mavContainer ) ;
if ( ! attrMethod . isVoid ( ) ) {
String returnValueName = getNameForReturnValue ( returnValue , attrMethod . getReturnType ( ) ) ;
if ( ! mavContainer . containsAttribute ( returnValueName ) ) {
mavContainer . addAttribute ( returnValueName , returnValue ) ;
Object returnValue = modelMethod . invokeForRequest ( request , container ) ;
if ( ! modelMethod . isVoid ( ) ) {
String returnValueName = getNameForReturnValue ( returnValue , modelMethod . getReturnType ( ) ) ;
if ( ! container . containsAttribute ( returnValueName ) ) {
container . addAttribute ( returnValueName , returnValue ) ;
}
}
}
}
private ModelMethod getNextModelMethod ( ModelAndViewContainer mavC ontainer) {
private ModelMethod getNextModelMethod ( ModelAndViewContainer c ontainer) {
for ( ModelMethod modelMethod : this . modelMethods ) {
if ( modelMethod . checkDependencies ( mavC ontainer) ) {
if ( modelMethod . checkDependencies ( c ontainer) ) {
if ( logger . isTraceEnabled ( ) ) {
logger . trace ( "Selected @ModelAttribute method " + modelMethod ) ;
}
@ -157,7 +156,7 @@ public final class ModelFactory {
@@ -157,7 +156,7 @@ public final class ModelFactory {
ModelMethod modelMethod = this . modelMethods . get ( 0 ) ;
if ( logger . isTraceEnabled ( ) ) {
logger . trace ( "Selected @ModelAttribute method (not present: " +
modelMethod . getUnresolvedDependencies ( mavC ontainer) + ") " + modelMethod ) ;
modelMethod . getUnresolvedDependencies ( c ontainer) + ") " + modelMethod ) ;
}
this . modelMethods . remove ( modelMethod ) ;
return modelMethod ;
@ -171,7 +170,8 @@ public final class ModelFactory {
@@ -171,7 +170,8 @@ public final class ModelFactory {
for ( MethodParameter parameter : handlerMethod . getMethodParameters ( ) ) {
if ( parameter . hasParameterAnnotation ( ModelAttribute . class ) ) {
String name = getNameForParameter ( parameter ) ;
if ( this . sessionAttributesHandler . isHandlerSessionAttribute ( name , parameter . getParameterType ( ) ) ) {
Class < ? > paramType = parameter . getParameterType ( ) ;
if ( this . sessionAttributesHandler . isHandlerSessionAttribute ( name , paramType ) ) {
result . add ( name ) ;
}
}
@ -182,36 +182,37 @@ public final class ModelFactory {
@@ -182,36 +182,37 @@ public final class ModelFactory {
/ * *
* Derives the model attribute name for a method parameter based on :
* < ol >
* < li > The parameter { @code @ModelAttribute } annotation value
* < li > The parameter type
* < li > The parameter { @code @ModelAttribute } annotation value
* < li > The parameter type
* < / ol >
* @return the derived name ; never { @code null } or an empty string
* /
public static String getNameForParameter ( MethodParameter parameter ) {
ModelAttribute annot = parameter . getParameterAnnotation ( ModelAttribute . class ) ;
String attrN ame = ( annot ! = null ) ? annot . value ( ) : null ;
return StringUtils . hasText ( attrName ) ? attrName : Conventions . getVariableNameForParameter ( parameter ) ;
ModelAttribute ann = parameter . getParameterAnnotation ( ModelAttribute . class ) ;
String n ame = ( ann ! = null ? ann . value ( ) : null ) ;
return StringUtils . hasText ( name ) ? name : Conventions . getVariableNameForParameter ( parameter ) ;
}
/ * *
* Derive the model attribute name for the given return value using one of :
* < ol >
* < li > The method { @code ModelAttribute } annotation value
* < li > The declared return type if it is more specific than { @code Object }
* < li > The actual return value type
* < li > The method { @code ModelAttribute } annotation value
* < li > The declared return type if it is more specific than { @code Object }
* < li > The actual return value type
* < / ol >
* @param returnValue the value returned from a method invocation
* @param returnType the return type of the method
* @return the model name , never { @code null } nor empty
* /
public static String getNameForReturnValue ( Object returnValue , MethodParameter returnType ) {
ModelAttribute annotation = returnType . getMethodAnnotation ( ModelAttribute . class ) ;
if ( annotation ! = null & & StringUtils . hasText ( annotatio n . value ( ) ) ) {
return annotation . value ( ) ;
ModelAttribute ann = returnType . getMethodAnnotation ( ModelAttribute . class ) ;
if ( ann ! = null & & StringUtils . hasText ( ann . value ( ) ) ) {
return ann . value ( ) ;
}
else {
Method method = returnType . getMethod ( ) ;
Class < ? > resolvedType = GenericTypeResolver . resolveReturnType ( method , returnType . getContainingClass ( ) ) ;
Class < ? > containingClass = returnType . getContainingClass ( ) ;
Class < ? > resolvedType = GenericTypeResolver . resolveReturnType ( method , containingClass ) ;
return Conventions . getVariableNameForReturnType ( method , resolvedType , returnValue ) ;
}
}
@ -220,18 +221,18 @@ public final class ModelFactory {
@@ -220,18 +221,18 @@ public final class ModelFactory {
* Promote model attributes listed as { @code @SessionAttributes } to the session .
* Add { @link BindingResult } attributes where necessary .
* @param request the current request
* @param mavC ontainer contains the model to update
* @param c ontainer contains the model to update
* @throws Exception if creating BindingResult attributes fails
* /
public void updateModel ( NativeWebRequest request , ModelAndViewContainer mavC ontainer) throws Exception {
ModelMap defaultModel = mavC ontainer. getDefaultModel ( ) ;
if ( mavC ontainer. getSessionStatus ( ) . isComplete ( ) ) {
public void updateModel ( NativeWebRequest request , ModelAndViewContainer c ontainer) throws Exception {
ModelMap defaultModel = c ontainer. getDefaultModel ( ) ;
if ( c ontainer. getSessionStatus ( ) . isComplete ( ) ) {
this . sessionAttributesHandler . cleanupAttributes ( request ) ;
}
else {
this . sessionAttributesHandler . storeAttributes ( request , defaultModel ) ;
}
if ( ! mavC ontainer. isRequestHandled ( ) & & mavC ontainer. getModel ( ) = = defaultModel ) {
if ( ! c ontainer. isRequestHandled ( ) & & c ontainer. getModel ( ) = = defaultModel ) {
updateBindingResult ( request , defaultModel ) ;
}
}
@ -248,7 +249,7 @@ public final class ModelFactory {
@@ -248,7 +249,7 @@ public final class ModelFactory {
String bindingResultKey = BindingResult . MODEL_KEY_PREFIX + name ;
if ( ! model . containsAttribute ( bindingResultKey ) ) {
WebDataBinder dataBinder = dataBinderFactory . createBinder ( request , value , name ) ;
WebDataBinder dataBinder = this . dataBinderFactory . createBinder ( request , value , name ) ;
model . put ( bindingResultKey , dataBinder . getBindingResult ( ) ) ;
}
}
@ -279,7 +280,6 @@ public final class ModelFactory {
@@ -279,7 +280,6 @@ public final class ModelFactory {
private final Set < String > dependencies = new HashSet < String > ( ) ;
private ModelMethod ( InvocableHandlerMethod handlerMethod ) {
this . handlerMethod = handlerMethod ;
for ( MethodParameter parameter : handlerMethod . getMethodParameters ( ) ) {