@ -110,7 +110,7 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
@@ -110,7 +110,7 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
parameter . getGenericParameterType ( ) ) ;
String name = ModelInitializer . getNameForParameter ( parameter ) ;
Mono < ? > valu eMono = prepareAttributeMono ( name , valueType , context , exchange ) ;
Mono < ? > attribut eMono = prepareAttributeMono ( name , valueType , context , exchange ) ;
// unsafe(): we're intercepting, already serialized Publisher signals
Sinks . One < BindingResult > bindingResultSink = Sinks . unsafe ( ) . one ( ) ;
@ -118,15 +118,15 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
@@ -118,15 +118,15 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
Map < String , Object > model = context . getModel ( ) . asMap ( ) ;
model . put ( BindingResult . MODEL_KEY_PREFIX + name , bindingResultSink . asMono ( ) ) ;
return valu eMono. flatMap ( valu e - > {
WebExchangeDataBinder binder = context . createDataBinder ( exchange , valu e, name , parameter ) ;
return ( bindingDisabled ( parameter ) ? Mono . empty ( ) : bindRequestParameters ( binder , exchange ) )
return attribut eMono. flatMap ( attribut e - > {
WebExchangeDataBinder binder = context . createDataBinder ( exchange , attribut e, name , parameter ) ;
return ( ! bindingDisabled ( parameter ) ? bindRequestParameters ( binder , exchange ) : Mono . empty ( ) )
. doOnError ( bindingResultSink : : tryEmitError )
. doOnSuccess ( aVoid - > {
validateIfApplicable ( binder , parameter , exchange ) ;
BindingResult bindingResult = binder . getBindingResult ( ) ;
model . put ( BindingResult . MODEL_KEY_PREFIX + name , bindingResult ) ;
model . put ( name , valu e) ;
model . put ( name , attribut e) ;
// Ignore result: serialized and buffered (should never fail)
bindingResultSink . tryEmitValue ( bindingResult ) ;
} )
@ -134,82 +134,51 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
@@ -134,82 +134,51 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
BindingResult errors = binder . getBindingResult ( ) ;
if ( adapter ! = null ) {
return adapter . fromPublisher ( errors . hasErrors ( ) ?
Mono . error ( new WebExchangeBindException ( parameter , errors ) ) : valu eMono) ;
Mono . error ( new WebExchangeBindException ( parameter , errors ) ) : attribut eMono) ;
}
else {
if ( errors . hasErrors ( ) & & ! hasErrorsArgument ( parameter ) ) {
throw new WebExchangeBindException ( parameter , errors ) ;
}
return valu e;
return attribut e;
}
} ) ) ;
} ) ;
}
/ * *
* Determine if binding should be disabled for the supplied { @link MethodParameter } ,
* based on the { @link ModelAttribute # binding } annotation attribute .
* @since 5 . 2 . 15
* /
private boolean bindingDisabled ( MethodParameter parameter ) {
ModelAttribute modelAttribute = parameter . getParameterAnnotation ( ModelAttribute . class ) ;
return ( modelAttribute ! = null & & ! modelAttribute . binding ( ) ) ;
}
/ * *
* Extension point to bind the request to the target object .
* @param binder the data binder instance to use for the binding
* @param exchange the current request
* @since 5 . 2 . 6
* /
protected Mono < Void > bindRequestParameters ( WebExchangeDataBinder binder , ServerWebExchange exchange ) {
return binder . bind ( exchange ) ;
}
private Mono < ? > prepareAttributeMono ( String attributeName , ResolvableType attributeType ,
BindingContext context , ServerWebExchange exchange ) {
private Mono < ? > prepareAttributeMono (
String name , ResolvableType type , BindingContext context , ServerWebExchange exchange ) {
Object attribute = context . getModel ( ) . asMap ( ) . get ( attributeN ame) ;
Object attribute = context . getModel ( ) . asMap ( ) . get ( name ) ;
if ( attribute = = null ) {
attribute = findAndR emoveReactiveAttribute( context . getModel ( ) , attributeN ame) ;
attribute = removeReactiveAttribute ( context . getModel ( ) , name ) ;
}
if ( attribute = = null ) {
return createAttribute ( attributeN ame, a ttributeT ype. toClass ( ) , context , exchange ) ;
return createAttribute ( name , type . toClass ( ) , context , exchange ) ;
}
ReactiveAdapter adapter = getAdapterRegistry ( ) . getAdapter ( null , attribute ) ;
if ( adapter ! = null ) {
Assert . isTrue ( ! adapter . isMultiValue ( ) , "Data binding only supports single-value async types" ) ;
return Mono . from ( adapter . toPublisher ( attribute ) ) ;
}
else {
return Mono . justOrEmpty ( attribute ) ;
}
Assert . isTrue ( adapter = = null | | ! adapter . isMultiValue ( ) , "Model attribute must be single-value publisher" ) ;
return ( adapter ! = null ? Mono . from ( adapter . toPublisher ( attribute ) ) : Mono . justOrEmpty ( attribute ) ) ;
}
@Nullable
private Object findAndR emoveReactiveAttribute( Model model , String attributeN ame) {
return model . asMap ( ) . entrySet ( ) . stream ( )
. filter ( entry - > {
if ( ! entry . getKey ( ) . startsWith ( attributeName ) ) {
return false ;
}
ReactiveAdapter adapter = getAdapterRegistry ( ) . getAdapter ( null , entry . getValue ( ) ) ;
if ( adapter = = null ) {
return false ;
private Object removeReactiveAttribute ( Model model , String name ) {
for ( Map . Entry < String , Object > entry : model . asMap ( ) . entrySet ( ) ) {
if ( entry . getKey ( ) . startsWith ( name ) ) {
ReactiveAdapter adapter = getAdapterRegistry ( ) . getAdapter ( null , entry . getValue ( ) ) ;
if ( adapter ! = null ) {
if ( entry . getKey ( ) . equals ( name + ClassUtils . getShortName ( adapter . getReactiveType ( ) ) ) ) {
// Remove since we will be re-inserting the resolved attribute value
model . asMap ( ) . remove ( entry . getKey ( ) ) ;
return entry . getValue ( ) ;
}
String name = attributeName + ClassUtils . getShortName ( adapter . getReactiveType ( ) ) ;
return entry . getKey ( ) . equals ( name ) ;
} )
. findFirst ( )
. map ( entry - > {
// Remove since we will be re-inserting the resolved attribute value
model . asMap ( ) . remove ( entry . getKey ( ) ) ;
return entry . getValue ( ) ;
} )
. orElse ( null ) ;
}
}
}
return null ;
}
private Mono < ? > createAttribute (
@ -274,6 +243,26 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
@@ -274,6 +243,26 @@ public class ModelAttributeMethodArgumentResolver extends HandlerMethodArgumentR
return binder . getValuesToBind ( exchange ) ;
}
/ * *
* Determine if binding should be disabled for the supplied { @link MethodParameter } ,
* based on the { @link ModelAttribute # binding } annotation attribute .
* @since 5 . 2 . 15
* /
private boolean bindingDisabled ( MethodParameter parameter ) {
ModelAttribute modelAttribute = parameter . getParameterAnnotation ( ModelAttribute . class ) ;
return ( modelAttribute ! = null & & ! modelAttribute . binding ( ) ) ;
}
/ * *
* Extension point to bind the request to the target object .
* @param binder the data binder instance to use for the binding
* @param exchange the current request
* @since 5 . 2 . 6
* /
protected Mono < Void > bindRequestParameters ( WebExchangeDataBinder binder , ServerWebExchange exchange ) {
return binder . bind ( exchange ) ;
}
private boolean hasErrorsArgument ( MethodParameter parameter ) {
int i = parameter . getParameterIndex ( ) ;
Class < ? > [ ] paramTypes = parameter . getExecutable ( ) . getParameterTypes ( ) ;