2525import java .util .List ;
2626import java .util .Locale ;
2727import java .util .Map ;
28+ import java .util .TreeMap ;
2829
2930import org .junit .Before ;
3031import org .junit .Test ;
4546import org .springframework .http .server .reactive .ServerHttpResponse ;
4647import org .springframework .mock .http .server .reactive .test .MockServerHttpRequest ;
4748import org .springframework .mock .http .server .reactive .test .MockServerHttpResponse ;
48- import org .springframework .ui .ExtendedModelMap ;
49+ import org .springframework .ui .ConcurrentModel ;
4950import org .springframework .ui .Model ;
5051import org .springframework .web .bind .annotation .ModelAttribute ;
5152import org .springframework .web .bind .annotation .ResponseStatus ;
5253import org .springframework .web .reactive .HandlerResult ;
5354import org .springframework .web .reactive .accept .HeaderContentTypeResolver ;
5455import org .springframework .web .reactive .accept .RequestedContentTypeResolver ;
5556import org .springframework .web .reactive .result .ResolvableMethod ;
57+ import org .springframework .web .reactive .result .method .BindingContext ;
5658import org .springframework .web .server .NotAcceptableStatusException ;
5759import org .springframework .web .server .ServerWebExchange ;
5860import org .springframework .web .server .adapter .DefaultServerWebExchange ;
6163
6264import static java .nio .charset .StandardCharsets .UTF_8 ;
6365import static org .junit .Assert .assertEquals ;
64- import static org .junit .Assert .assertNotNull ;
6566import static org .mockito .Mockito .mock ;
6667import static org .springframework .core .ResolvableType .forClass ;
6768import static org .springframework .core .ResolvableType .forClassWithGenerics ;
@@ -80,7 +81,7 @@ public class ViewResolutionResultHandlerTests {
8081
8182 private ServerWebExchange exchange ;
8283
83- private Model model = new ExtendedModelMap ();
84+ private final BindingContext bindingContext = new BindingContext ();
8485
8586
8687 @ Before
@@ -114,7 +115,7 @@ private void testSupports(ResolvableType type, boolean result) {
114115 private void testSupports (ResolvableMethod resolvableMethod , boolean result ) {
115116 ViewResolutionResultHandler resultHandler = resultHandler (mock (ViewResolver .class ));
116117 MethodParameter returnType = resolvableMethod .resolveReturnType ();
117- HandlerResult handlerResult = new HandlerResult (new Object (), null , returnType , this .model );
118+ HandlerResult handlerResult = new HandlerResult (new Object (), null , returnType , this .bindingContext );
118119 assertEquals (result , resultHandler .supports (handlerResult ));
119120 }
120121
@@ -156,7 +157,7 @@ public void handleReturnValueTypes() throws Exception {
156157 assertEquals (HttpStatus .PARTIAL_CONTENT , this .exchange .getResponse ().getStatusCode ());
157158
158159 returnType = forClass (Model .class );
159- returnValue = new ExtendedModelMap ().addAttribute ("name" , "Joe" );
160+ returnValue = new ConcurrentModel ().addAttribute ("name" , "Joe" );
160161 testHandle ("/account" , returnType , returnValue , "account: {id=123, name=Joe}" , resolver );
161162
162163 returnType = forClass (Map .class );
@@ -190,8 +191,8 @@ public void defaultViewName() throws Exception {
190191 }
191192
192193 private void testDefaultViewName (Object returnValue , ResolvableType type ) throws URISyntaxException {
193- Model model = new ExtendedModelMap ().addAttribute ("id" , "123" );
194- HandlerResult result = new HandlerResult (new Object (), returnValue , returnType (type ), model );
194+ this . bindingContext . getModel ().addAttribute ("id" , "123" );
195+ HandlerResult result = new HandlerResult (new Object (), returnValue , returnType (type ), this . bindingContext );
195196 ViewResolutionResultHandler handler = resultHandler (new TestViewResolver ("account" ));
196197
197198 this .request .setUri ("/account" );
@@ -210,8 +211,8 @@ private void testDefaultViewName(Object returnValue, ResolvableType type) throws
210211 @ Test
211212 public void unresolvedViewName () throws Exception {
212213 String returnValue = "account" ;
213- ResolvableType type = forClass (String .class );
214- HandlerResult result = new HandlerResult (new Object (), returnValue , returnType ( type ) , this .model );
214+ MethodParameter returnType = returnType ( forClass (String .class ) );
215+ HandlerResult result = new HandlerResult (new Object (), returnValue , returnType , this .bindingContext );
215216
216217 this .request .setUri ("/path" );
217218 Mono <Void > mono = resultHandler ().handleResult (this .exchange , result );
@@ -225,8 +226,8 @@ public void unresolvedViewName() throws Exception {
225226 @ Test
226227 public void contentNegotiation () throws Exception {
227228 TestBean value = new TestBean ("Joe" );
228- ResolvableType type = forClass (TestBean .class );
229- HandlerResult handlerResult = new HandlerResult (new Object (), value , returnType ( type ) , this .model );
229+ MethodParameter returnType = returnType ( forClass (TestBean .class ) );
230+ HandlerResult handlerResult = new HandlerResult (new Object (), value , returnType , this .bindingContext );
230231
231232 this .request .setHeader ("Accept" , "application/json" );
232233 this .request .setUri ("/account" );
@@ -244,8 +245,8 @@ public void contentNegotiation() throws Exception {
244245 @ Test
245246 public void contentNegotiationWith406 () throws Exception {
246247 TestBean value = new TestBean ("Joe" );
247- ResolvableType type = forClass (TestBean .class );
248- HandlerResult handlerResult = new HandlerResult (new Object (), value , returnType ( type ) , this .model );
248+ MethodParameter returnType = returnType ( forClass (TestBean .class ) );
249+ HandlerResult handlerResult = new HandlerResult (new Object (), value , returnType , this .bindingContext );
249250
250251 this .request .setHeader ("Accept" , "application/json" );
251252 this .request .setUri ("/account" );
@@ -260,13 +261,13 @@ public void contentNegotiationWith406() throws Exception {
260261
261262 @ Test
262263 public void modelWithAsyncAttributes () throws Exception {
263- Model model = new ExtendedModelMap ();
264- model .addAttribute ("bean1" , Mono .just (new TestBean ("Bean1" )));
265- model .addAttribute ("bean2" , Single .just (new TestBean ("Bean2" )));
266- model .addAttribute ("empty" , Mono .empty ());
264+ this . bindingContext . getModel ()
265+ .addAttribute ("bean1" , Mono .just (new TestBean ("Bean1" )))
266+ .addAttribute ("bean2" , Single .just (new TestBean ("Bean2" )))
267+ .addAttribute ("empty" , Mono .empty ());
267268
268269 ResolvableType type = forClass (void .class );
269- HandlerResult result = new HandlerResult (new Object (), null , returnType (type ), model );
270+ HandlerResult result = new HandlerResult (new Object (), null , returnType (type ), this . bindingContext );
270271 ViewResolutionResultHandler handler = resultHandler (new TestViewResolver ("account" ));
271272
272273 this .request .setUri ("/account" );
@@ -304,9 +305,11 @@ private void testHandle(String path, ResolvableType returnType, Object returnVal
304305 private void testHandle (String path , ResolvableMethod resolvableMethod , Object returnValue ,
305306 String responseBody , ViewResolver ... resolvers ) throws URISyntaxException {
306307
307- Model model = new ExtendedModelMap ().addAttribute ("id" , "123" );
308+ Model model = this .bindingContext .getModel ();
309+ model .asMap ().clear ();
310+ model .addAttribute ("id" , "123" );
308311 MethodParameter returnType = resolvableMethod .resolveReturnType ();
309- HandlerResult result = new HandlerResult (new Object (), returnValue , returnType , model );
312+ HandlerResult result = new HandlerResult (new Object (), returnValue , returnType , this . bindingContext );
310313 this .request .setUri (path );
311314 resultHandler (resolvers ).handleResult (this .exchange , result ).block (Duration .ofSeconds (5 ));
312315 assertResponseBody (responseBody );
@@ -375,12 +378,12 @@ public List<MediaType> getSupportedMediaTypes() {
375378
376379 @ Override
377380 public Mono <Void > render (Map <String , ?> model , MediaType mediaType , ServerWebExchange exchange ) {
378- String value = this .name + ": " + model .toString ();
379- assertNotNull (value );
380381 ServerHttpResponse response = exchange .getResponse ();
381382 if (mediaType != null ) {
382383 response .getHeaders ().setContentType (mediaType );
383384 }
385+ model = new TreeMap <>(model );
386+ String value = this .name + ": " + model .toString ();
384387 ByteBuffer byteBuffer = ByteBuffer .wrap (value .getBytes (UTF_8 ));
385388 DataBuffer dataBuffer = new DefaultDataBufferFactory ().wrap (byteBuffer );
386389 return response .writeWith (Flux .just (dataBuffer ));
0 commit comments