@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
@@ -25,6 +25,7 @@ import java.util.LinkedHashMap;
import java.util.List ;
import java.util.Map ;
import org.apache.groovy.util.Maps ;
import org.junit.jupiter.api.BeforeAll ;
import org.junit.jupiter.api.BeforeEach ;
import org.junit.jupiter.api.Test ;
@ -45,6 +46,8 @@ import org.springframework.lang.Nullable;
@@ -45,6 +46,8 @@ import org.springframework.lang.Nullable;
import org.springframework.ui.Model ;
import org.springframework.web.bind.annotation.ControllerAdvice ;
import org.springframework.web.bind.annotation.ModelAttribute ;
import org.springframework.web.bind.annotation.RequestBody ;
import org.springframework.web.bind.annotation.ResponseBody ;
import org.springframework.web.bind.annotation.SessionAttributes ;
import org.springframework.web.context.support.StaticWebApplicationContext ;
import org.springframework.web.method.HandlerMethod ;
@ -109,7 +112,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -109,7 +112,7 @@ public class RequestMappingHandlerAdapterTests {
@Test
public void cacheControlWithoutSessionAttributes ( ) throws Exception {
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handle" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handle" ) ;
this . handlerAdapter . setCacheSeconds ( 100 ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
@ -197,7 +200,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -197,7 +200,7 @@ public class RequestMappingHandlerAdapterTests {
this . webAppContext . registerSingleton ( "maa" , ModelAttributeAdvice . class ) ;
this . webAppContext . refresh ( ) ;
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handle" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handle" ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
ModelAndView mav = this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) ;
@ -210,7 +213,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -210,7 +213,7 @@ public class RequestMappingHandlerAdapterTests {
this . webAppContext . registerPrototype ( "maa" , ModelAttributeAdvice . class ) ;
this . webAppContext . refresh ( ) ;
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handle" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handle" ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
Map < String , Object > model1 = this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) . getModel ( ) ;
Map < String , Object > model2 = this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) . getModel ( ) ;
@ -226,7 +229,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -226,7 +229,7 @@ public class RequestMappingHandlerAdapterTests {
this . webAppContext . setParent ( parent ) ;
this . webAppContext . refresh ( ) ;
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handle" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handle" ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
ModelAndView mav = this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) ;
@ -240,7 +243,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -240,7 +243,7 @@ public class RequestMappingHandlerAdapterTests {
this . webAppContext . registerSingleton ( "manupa" , ModelAttributeNotUsedPackageAdvice . class ) ;
this . webAppContext . refresh ( ) ;
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handle" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handle" ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
ModelAndView mav = this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) ;
@ -249,9 +252,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -249,9 +252,7 @@ public class RequestMappingHandlerAdapterTests {
assertThat ( mav . getModel ( ) . get ( "attr3" ) ) . isNull ( ) ;
}
// SPR-10859
@Test
@Test // gh-15486
public void responseBodyAdvice ( ) throws Exception {
List < HttpMessageConverter < ? > > converters = new ArrayList < > ( ) ;
converters . add ( new MappingJackson2HttpMessageConverter ( ) ) ;
@ -263,7 +264,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -263,7 +264,7 @@ public class RequestMappingHandlerAdapterTests {
this . request . addHeader ( "Accept" , MediaType . APPLICATION_JSON_VALUE ) ;
this . request . setParameter ( "c" , "callback" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Simple Controller( ) , "handleBadRequest" ) ;
HandlerMethod handlerMethod = handlerMethod ( new Test Controller( ) , "handleBadRequest" ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) ;
@ -271,6 +272,19 @@ public class RequestMappingHandlerAdapterTests {
@@ -271,6 +272,19 @@ public class RequestMappingHandlerAdapterTests {
assertThat ( this . response . getContentAsString ( ) ) . isEqualTo ( "{\"status\":400,\"message\":\"body\"}" ) ;
}
@Test // gh-30522
public void responseBodyAdviceWithEmptyBody ( ) throws Exception {
this . webAppContext . registerBean ( "rba" , EmptyBodyAdvice . class ) ;
this . webAppContext . refresh ( ) ;
HandlerMethod handlerMethod = handlerMethod ( new TestController ( ) , "handleBody" , Map . class ) ;
this . handlerAdapter . afterPropertiesSet ( ) ;
this . handlerAdapter . handle ( this . request , this . response , handlerMethod ) ;
assertThat ( this . response . getStatus ( ) ) . isEqualTo ( 200 ) ;
assertThat ( this . response . getContentAsString ( ) ) . isEqualTo ( "Body: {foo=bar}" ) ;
}
private HandlerMethod handlerMethod ( Object handler , String methodName , Class < ? > . . . paramTypes ) throws Exception {
Method method = handler . getClass ( ) . getDeclaredMethod ( methodName , paramTypes ) ;
return new InvocableHandlerMethod ( handler , method ) ;
@ -284,7 +298,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -284,7 +298,7 @@ public class RequestMappingHandlerAdapterTests {
@SuppressWarnings ( "unused" )
private static class Simple Controller {
private static class Test Controller {
@ModelAttribute
public void addAttributes ( Model model ) {
@ -296,14 +310,17 @@ public class RequestMappingHandlerAdapterTests {
@@ -296,14 +310,17 @@ public class RequestMappingHandlerAdapterTests {
}
public ResponseEntity < Map < String , String > > handleWithResponseEntity ( ) {
return new ResponseEntity < > ( Collections . singletonMap (
"foo" , "bar" ) , HttpStatus . OK ) ;
return new ResponseEntity < > ( Collections . singletonMap ( "foo" , "bar" ) , HttpStatus . OK ) ;
}
public ResponseEntity < String > handleBadRequest ( ) {
return new ResponseEntity < > ( "body" , HttpStatus . BAD_REQUEST ) ;
}
@ResponseBody
public String handleBody ( @Nullable @RequestBody Map < String , String > body ) {
return "Body: " + body ;
}
}
@ -360,6 +377,7 @@ public class RequestMappingHandlerAdapterTests {
@@ -360,6 +377,7 @@ public class RequestMappingHandlerAdapterTests {
}
}
/ * *
* This class additionally implements { @link RequestBodyAdvice } solely for the purpose
* of verifying that controller advice implementing both { @link ResponseBodyAdvice }
@ -368,7 +386,8 @@ public class RequestMappingHandlerAdapterTests {
@@ -368,7 +386,8 @@ public class RequestMappingHandlerAdapterTests {
* @see < a href = "https://github.com/spring-projects/spring-framework/pull/22638" > gh - 22638 < / a >
* /
@ControllerAdvice
private static class ResponseCodeSuppressingAdvice extends AbstractMappingJacksonResponseBodyAdvice implements RequestBodyAdvice {
private static class ResponseCodeSuppressingAdvice
extends AbstractMappingJacksonResponseBodyAdvice implements RequestBodyAdvice {
@Override
protected void beforeBodyWriteInternal ( MappingJacksonValue bodyContainer , MediaType contentType ,
@ -405,12 +424,42 @@ public class RequestMappingHandlerAdapterTests {
@@ -405,12 +424,42 @@ public class RequestMappingHandlerAdapterTests {
}
@Override
public Object handleEmptyBody ( @Nullable Object body , HttpInputMessage inputMessage , MethodParameter parameter ,
public Object handleEmptyBody ( Object body , HttpInputMessage inputMessage , MethodParameter parameter ,
Type targetType , Class < ? extends HttpMessageConverter < ? > > converterType ) {
return "default value for empty body" ;
}
}
@ControllerAdvice
private static class EmptyBodyAdvice implements RequestBodyAdvice {
@Override
public boolean supports ( MethodParameter param , Type targetType , Class < ? extends HttpMessageConverter < ? > > type ) {
return true ;
}
@Override
public HttpInputMessage beforeBodyRead ( HttpInputMessage message , MethodParameter param ,
Type targetType , Class < ? extends HttpMessageConverter < ? > > type ) {
throw new UnsupportedOperationException ( ) ;
}
@Override
public Object afterBodyRead ( Object body , HttpInputMessage message , MethodParameter param ,
Type targetType , Class < ? extends HttpMessageConverter < ? > > type ) {
throw new UnsupportedOperationException ( ) ;
}
@Override
public Object handleEmptyBody ( Object body , HttpInputMessage message , MethodParameter param ,
Type targetType , Class < ? extends HttpMessageConverter < ? > > type ) {
return Maps . of ( "foo" , "bar" ) ;
}
}
}