46
46
import org .springframework .web .reactive .result .condition .ConsumesRequestCondition ;
47
47
import org .springframework .web .reactive .result .condition .MediaTypeExpression ;
48
48
import org .springframework .web .reactive .result .method .RequestMappingInfo ;
49
+ import org .springframework .web .server .ServerWebExchange ;
49
50
import org .springframework .web .service .annotation .HttpExchange ;
50
51
import org .springframework .web .service .annotation .PostExchange ;
51
52
import org .springframework .web .service .annotation .PutExchange ;
53
+ import org .springframework .web .testfixture .http .server .reactive .MockServerHttpRequest ;
54
+ import org .springframework .web .testfixture .server .MockServerWebExchange ;
52
55
import org .springframework .web .util .pattern .PathPattern ;
53
56
import org .springframework .web .util .pattern .PathPatternParser ;
54
57
55
58
import static org .assertj .core .api .Assertions .assertThat ;
56
59
import static org .assertj .core .api .Assertions .assertThatIllegalStateException ;
57
60
import static org .mockito .Mockito .mock ;
61
+ import static org .springframework .web .bind .annotation .RequestMethod .POST ;
62
+ import static org .springframework .web .reactive .result .method .RequestMappingInfo .paths ;
58
63
59
64
/**
60
65
* Tests for {@link RequestMappingHandlerMapping}.
@@ -110,7 +115,7 @@ void resolveRequestMappingViaComposedAnnotation() {
110
115
}
111
116
112
117
@ Test // SPR-14988
113
- void getMappingOverridesConsumesFromTypeLevelAnnotation () {
118
+ void postMappingOverridesConsumesFromTypeLevelAnnotation () {
114
119
RequestMappingInfo requestMappingInfo = assertComposedAnnotationMapping (RequestMethod .POST );
115
120
116
121
ConsumesRequestCondition condition = requestMappingInfo .getConsumesCondition ();
@@ -323,10 +328,13 @@ void httpExchangeWithCustomHeaders() {
323
328
.containsExactly ("h1=hv1" , "!h2" );
324
329
}
325
330
326
- @ Test
331
+ @ Test // gh-35086
327
332
void requestBodyAnnotationFromInterfaceIsRespected () {
328
333
this .handlerMapping .afterPropertiesSet ();
329
334
335
+ String path = "/controller/postMapping" ;
336
+ MediaType mediaType = MediaType .APPLICATION_JSON ;
337
+
330
338
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
331
339
mapping .setApplicationContext (new StaticWebApplicationContext ());
332
340
mapping .afterPropertiesSet ();
@@ -338,16 +346,37 @@ void requestBodyAnnotationFromInterfaceIsRespected() {
338
346
RequestMappingInfo info = mapping .getMappingForMethod (method , clazz );
339
347
assertThat (info ).isNotNull ();
340
348
349
+ // Original ConsumesCondition
350
+ ConsumesRequestCondition consumesCondition = info .getConsumesCondition ();
351
+ assertThat (consumesCondition ).isNotNull ();
352
+ assertThat (consumesCondition .isBodyRequired ()).isTrue ();
353
+ assertThat (consumesCondition .getConsumableMediaTypes ()).containsOnly (mediaType );
354
+
341
355
mapping .registerHandlerMethod (new InterfaceControllerImpl (), method , info );
342
- assertThat (info .getConsumesCondition ()).isNotNull ();
343
- assertThat (info .getConsumesCondition ().isBodyRequired ()).isFalse ();
344
- assertThat (info .getConsumesCondition ().getConsumableMediaTypes ()).containsOnly (MediaType .APPLICATION_JSON );
356
+
357
+ // Updated ConsumesCondition
358
+ consumesCondition = info .getConsumesCondition ();
359
+ assertThat (consumesCondition ).isNotNull ();
360
+ assertThat (consumesCondition .isBodyRequired ()).isFalse ();
361
+ assertThat (consumesCondition .getConsumableMediaTypes ()).containsOnly (mediaType );
362
+
363
+ MockServerHttpRequest request = MockServerHttpRequest .post (path )
364
+ .contentType (mediaType ).build ();
365
+ ServerWebExchange exchange = MockServerWebExchange .from (request );
366
+ RequestMappingInfo matchingInfo = info .getMatchingCondition (exchange );
367
+ // Since the request has no body AND the required flag is false, the
368
+ // ConsumesCondition in the matching condition in an EMPTY_CONDITION.
369
+ // In other words, the "consumes" expressions are removed.
370
+ assertThat (matchingInfo ).isEqualTo (paths (path ).methods (POST ).build ());
345
371
}
346
372
347
- @ Test
373
+ @ Test // gh-35086
348
374
void requestBodyAnnotationFromImplementationOverridesInterface () {
349
375
this .handlerMapping .afterPropertiesSet ();
350
376
377
+ String path = "/controller/postMapping" ;
378
+ MediaType mediaType = MediaType .APPLICATION_JSON ;
379
+
351
380
RequestMappingHandlerMapping mapping = new RequestMappingHandlerMapping ();
352
381
mapping .setApplicationContext (new StaticWebApplicationContext ());
353
382
mapping .afterPropertiesSet ();
@@ -359,10 +388,25 @@ void requestBodyAnnotationFromImplementationOverridesInterface() {
359
388
RequestMappingInfo info = mapping .getMappingForMethod (method , clazz );
360
389
assertThat (info ).isNotNull ();
361
390
391
+ // Original ConsumesCondition
392
+ ConsumesRequestCondition consumesCondition = info .getConsumesCondition ();
393
+ assertThat (consumesCondition ).isNotNull ();
394
+ assertThat (consumesCondition .isBodyRequired ()).isTrue ();
395
+ assertThat (consumesCondition .getConsumableMediaTypes ()).containsOnly (mediaType );
396
+
362
397
mapping .registerHandlerMethod (new InterfaceControllerImplOverridesRequestBody (), method , info );
363
- assertThat (info .getConsumesCondition ()).isNotNull ();
364
- assertThat (info .getConsumesCondition ().isBodyRequired ()).isTrue ();
365
- assertThat (info .getConsumesCondition ().getConsumableMediaTypes ()).containsOnly (MediaType .APPLICATION_JSON );
398
+
399
+ // Updated ConsumesCondition
400
+ consumesCondition = info .getConsumesCondition ();
401
+ assertThat (consumesCondition ).isNotNull ();
402
+ assertThat (consumesCondition .isBodyRequired ()).isTrue ();
403
+ assertThat (consumesCondition .getConsumableMediaTypes ()).containsOnly (mediaType );
404
+
405
+ MockServerHttpRequest request = MockServerHttpRequest .post (path )
406
+ .contentType (mediaType ).build ();
407
+ ServerWebExchange exchange = MockServerWebExchange .from (request );
408
+ RequestMappingInfo matchingInfo = info .getMatchingCondition (exchange );
409
+ assertThat (matchingInfo ).isEqualTo (paths (path ).methods (POST ).consumes (mediaType .toString ()).build ());
366
410
}
367
411
368
412
private RequestMappingInfo assertComposedAnnotationMapping (RequestMethod requestMethod ) {
@@ -544,18 +588,21 @@ public void post() {}
544
588
}
545
589
546
590
@ Controller
547
- @ RequestMapping (value = "/controller" , consumes = { "application/json" } )
591
+ @ RequestMapping (path = "/controller" , consumes = "application/json" )
548
592
interface InterfaceController {
593
+
549
594
@ PostMapping ("/postMapping" )
550
595
void post (@ RequestBody (required = false ) Foo foo );
551
596
}
552
597
553
598
static class InterfaceControllerImpl implements InterfaceController {
599
+
554
600
@ Override
555
601
public void post (Foo foo ) {}
556
602
}
557
603
558
604
static class InterfaceControllerImplOverridesRequestBody implements InterfaceController {
605
+
559
606
@ Override
560
607
public void post (@ RequestBody (required = true ) Foo foo ) {}
561
608
}
0 commit comments