25
25
import java .util .List ;
26
26
import java .util .Map ;
27
27
28
+ import org .apache .groovy .util .Maps ;
28
29
import org .junit .jupiter .api .BeforeAll ;
29
30
import org .junit .jupiter .api .BeforeEach ;
30
31
import org .junit .jupiter .api .Test ;
45
46
import org .springframework .ui .Model ;
46
47
import org .springframework .web .bind .annotation .ControllerAdvice ;
47
48
import org .springframework .web .bind .annotation .ModelAttribute ;
49
+ import org .springframework .web .bind .annotation .RequestBody ;
50
+ import org .springframework .web .bind .annotation .ResponseBody ;
48
51
import org .springframework .web .bind .annotation .SessionAttributes ;
49
52
import org .springframework .web .context .support .StaticWebApplicationContext ;
50
53
import org .springframework .web .method .HandlerMethod ;
@@ -109,7 +112,7 @@ public void setup() throws Exception {
109
112
110
113
@ Test
111
114
public void cacheControlWithoutSessionAttributes () throws Exception {
112
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handle" );
115
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handle" );
113
116
this .handlerAdapter .setCacheSeconds (100 );
114
117
this .handlerAdapter .afterPropertiesSet ();
115
118
@@ -197,7 +200,7 @@ public void modelAttributeAdvice() throws Exception {
197
200
this .webAppContext .registerSingleton ("maa" , ModelAttributeAdvice .class );
198
201
this .webAppContext .refresh ();
199
202
200
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handle" );
203
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handle" );
201
204
this .handlerAdapter .afterPropertiesSet ();
202
205
ModelAndView mav = this .handlerAdapter .handle (this .request , this .response , handlerMethod );
203
206
@@ -210,7 +213,7 @@ public void prototypeControllerAdvice() throws Exception {
210
213
this .webAppContext .registerPrototype ("maa" , ModelAttributeAdvice .class );
211
214
this .webAppContext .refresh ();
212
215
213
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handle" );
216
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handle" );
214
217
this .handlerAdapter .afterPropertiesSet ();
215
218
Map <String , Object > model1 = this .handlerAdapter .handle (this .request , this .response , handlerMethod ).getModel ();
216
219
Map <String , Object > model2 = this .handlerAdapter .handle (this .request , this .response , handlerMethod ).getModel ();
@@ -226,7 +229,7 @@ public void modelAttributeAdviceInParentContext() throws Exception {
226
229
this .webAppContext .setParent (parent );
227
230
this .webAppContext .refresh ();
228
231
229
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handle" );
232
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handle" );
230
233
this .handlerAdapter .afterPropertiesSet ();
231
234
ModelAndView mav = this .handlerAdapter .handle (this .request , this .response , handlerMethod );
232
235
@@ -240,7 +243,7 @@ public void modelAttributePackageNameAdvice() throws Exception {
240
243
this .webAppContext .registerSingleton ("manupa" , ModelAttributeNotUsedPackageAdvice .class );
241
244
this .webAppContext .refresh ();
242
245
243
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handle" );
246
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handle" );
244
247
this .handlerAdapter .afterPropertiesSet ();
245
248
ModelAndView mav = this .handlerAdapter .handle (this .request , this .response , handlerMethod );
246
249
@@ -249,9 +252,7 @@ public void modelAttributePackageNameAdvice() throws Exception {
249
252
assertThat (mav .getModel ().get ("attr3" )).isNull ();
250
253
}
251
254
252
- // SPR-10859
253
-
254
- @ Test
255
+ @ Test // gh-15486
255
256
public void responseBodyAdvice () throws Exception {
256
257
List <HttpMessageConverter <?>> converters = new ArrayList <>();
257
258
converters .add (new MappingJackson2HttpMessageConverter ());
@@ -263,14 +264,27 @@ public void responseBodyAdvice() throws Exception {
263
264
this .request .addHeader ("Accept" , MediaType .APPLICATION_JSON_VALUE );
264
265
this .request .setParameter ("c" , "callback" );
265
266
266
- HandlerMethod handlerMethod = handlerMethod (new SimpleController (), "handleBadRequest" );
267
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handleBadRequest" );
267
268
this .handlerAdapter .afterPropertiesSet ();
268
269
this .handlerAdapter .handle (this .request , this .response , handlerMethod );
269
270
270
271
assertThat (this .response .getStatus ()).isEqualTo (200 );
271
272
assertThat (this .response .getContentAsString ()).isEqualTo ("{\" status\" :400,\" message\" :\" body\" }" );
272
273
}
273
274
275
+ @ Test // gh-30522
276
+ public void responseBodyAdviceWithEmptyBody () throws Exception {
277
+ this .webAppContext .registerBean ("rba" , EmptyBodyAdvice .class );
278
+ this .webAppContext .refresh ();
279
+
280
+ HandlerMethod handlerMethod = handlerMethod (new TestController (), "handleBody" , Map .class );
281
+ this .handlerAdapter .afterPropertiesSet ();
282
+ this .handlerAdapter .handle (this .request , this .response , handlerMethod );
283
+
284
+ assertThat (this .response .getStatus ()).isEqualTo (200 );
285
+ assertThat (this .response .getContentAsString ()).isEqualTo ("Body: {foo=bar}" );
286
+ }
287
+
274
288
private HandlerMethod handlerMethod (Object handler , String methodName , Class <?>... paramTypes ) throws Exception {
275
289
Method method = handler .getClass ().getDeclaredMethod (methodName , paramTypes );
276
290
return new InvocableHandlerMethod (handler , method );
@@ -284,7 +298,7 @@ private void assertMethodProcessorCount(int resolverCount, int initBinderResolve
284
298
285
299
286
300
@ SuppressWarnings ("unused" )
287
- private static class SimpleController {
301
+ private static class TestController {
288
302
289
303
@ ModelAttribute
290
304
public void addAttributes (Model model ) {
@@ -296,14 +310,17 @@ public String handle() {
296
310
}
297
311
298
312
public ResponseEntity <Map <String , String >> handleWithResponseEntity () {
299
- return new ResponseEntity <>(Collections .singletonMap (
300
- "foo" , "bar" ), HttpStatus .OK );
313
+ return new ResponseEntity <>(Collections .singletonMap ("foo" , "bar" ), HttpStatus .OK );
301
314
}
302
315
303
316
public ResponseEntity <String > handleBadRequest () {
304
317
return new ResponseEntity <>("body" , HttpStatus .BAD_REQUEST );
305
318
}
306
319
320
+ @ ResponseBody
321
+ public String handleBody (@ Nullable @ RequestBody Map <String , String > body ) {
322
+ return "Body: " + body ;
323
+ }
307
324
}
308
325
309
326
@@ -360,6 +377,7 @@ public void addAttributes(Model model) {
360
377
}
361
378
}
362
379
380
+
363
381
/**
364
382
* This class additionally implements {@link RequestBodyAdvice} solely for the purpose
365
383
* of verifying that controller advice implementing both {@link ResponseBodyAdvice}
@@ -368,7 +386,8 @@ public void addAttributes(Model model) {
368
386
* @see <a href="https://github.com/spring-projects/spring-framework/pull/22638">gh-22638</a>
369
387
*/
370
388
@ ControllerAdvice
371
- private static class ResponseCodeSuppressingAdvice extends AbstractMappingJacksonResponseBodyAdvice implements RequestBodyAdvice {
389
+ private static class ResponseCodeSuppressingAdvice
390
+ extends AbstractMappingJacksonResponseBodyAdvice implements RequestBodyAdvice {
372
391
373
392
@ Override
374
393
protected void beforeBodyWriteInternal (MappingJacksonValue bodyContainer , MediaType contentType ,
@@ -405,12 +424,42 @@ public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodPa
405
424
}
406
425
407
426
@ Override
408
- public Object handleEmptyBody (@ Nullable Object body , HttpInputMessage inputMessage , MethodParameter parameter ,
427
+ public Object handleEmptyBody (Object body , HttpInputMessage inputMessage , MethodParameter parameter ,
409
428
Type targetType , Class <? extends HttpMessageConverter <?>> converterType ) {
410
429
411
430
return "default value for empty body" ;
412
431
}
432
+ }
433
+
434
+
435
+ @ ControllerAdvice
436
+ private static class EmptyBodyAdvice implements RequestBodyAdvice {
437
+
438
+ @ Override
439
+ public boolean supports (MethodParameter param , Type targetType , Class <? extends HttpMessageConverter <?>> type ) {
440
+ return true ;
441
+ }
442
+
443
+ @ Override
444
+ public HttpInputMessage beforeBodyRead (HttpInputMessage message , MethodParameter param ,
445
+ Type targetType , Class <? extends HttpMessageConverter <?>> type ) {
446
+
447
+ throw new UnsupportedOperationException ();
448
+ }
413
449
450
+ @ Override
451
+ public Object afterBodyRead (Object body , HttpInputMessage message , MethodParameter param ,
452
+ Type targetType , Class <? extends HttpMessageConverter <?>> type ) {
453
+
454
+ throw new UnsupportedOperationException ();
455
+ }
456
+
457
+ @ Override
458
+ public Object handleEmptyBody (Object body , HttpInputMessage message , MethodParameter param ,
459
+ Type targetType , Class <? extends HttpMessageConverter <?>> type ) {
460
+
461
+ return Maps .of ("foo" , "bar" );
462
+ }
414
463
}
415
464
416
465
}
0 commit comments