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