@Test(expected = HttpMessageNotReadableException.class) // SPR-9942 public void resolveArgumentRequiredNoContent() throws Exception { this.servletRequest.setContent(new byte[0]); this.servletRequest.setContentType("text/plain"); List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.resolveArgument(paramString, container, request, factory); }
/** * Throws MethodArgumentNotValidException if validation fails. * @throws HttpMessageNotReadableException if {@link RequestBody#required()} * is {@code true} and there is no body content or if there is no suitable * converter to read the content with. */ @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { parameter = parameter.nestedIfOptional(); Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); String name = Conventions.getVariableNameForParameter(parameter); if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); if (arg != null) { validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } if (mavContainer != null) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } return adaptArgumentIfNecessary(arg, parameter); }
@Test(expected = IllegalArgumentException.class) public void handleReturnValueWithInvalidReturnType() throws Exception { Method method = getClass().getDeclaredMethod("handleAndReturnOutputStream"); MethodParameter returnType = new MethodParameter(method, -1); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(new ArrayList<>()); processor.writeWithMessageConverters(new ByteArrayOutputStream(), returnType, this.request); }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
@Override protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "No HttpServletRequest"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); Object arg = readWithMessageConverters(inputMessage, parameter, paramType); if (arg == null && checkRequired(parameter)) { throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage); } return arg; }
public ProxyExchange(RestTemplate rest, NativeWebRequest webRequest, ModelAndViewContainer mavContainer, WebDataBinderFactory binderFactory, Type type) { this.responseType = type; this.rest = rest; this.webRequest = webRequest; this.mavContainer = mavContainer; this.binderFactory = binderFactory; this.delegate = new RequestResponseBodyMethodProcessor( rest.getMessageConverters()); }
@Test public void handleReturnValueString() throws Exception { List<HttpMessageConverter<?>>converters = new ArrayList<>(); converters.add(new ByteArrayHttpMessageConverter()); converters.add(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.handleReturnValue("Foo", returnTypeString, container, request); assertEquals("text/plain;charset=ISO-8859-1", servletResponse.getHeader("Content-Type")); assertEquals("Foo", servletResponse.getContentAsString()); }
@Test // SPR-14520 public void resolveArgumentTypeVariableWithGenericInterface() throws Exception { this.servletRequest.setContent("\"foo\"".getBytes("UTF-8")); this.servletRequest.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); Method method = MyControllerImplementingInterface.class.getMethod("handle", Object.class); HandlerMethod handlerMethod = new HandlerMethod(new MyControllerImplementingInterface(), method); MethodParameter methodParameter = handlerMethod.getMethodParameters()[0]; List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); String value = (String) processor.readWithMessageConverters( this.request, methodParameter, methodParameter.getGenericParameterType()); assertEquals("foo", value); }
@Test public void supportsReturnTypeResponseBodyOnType() throws Exception { Method method = ResponseBodyController.class.getMethod("handle"); MethodParameter returnType = new MethodParameter(method, -1); List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertTrue("Failed to recognize type-level @ResponseBody", processor.supportsReturnType(returnType)); }
@Test(expected = HttpMediaTypeNotSupportedException.class) public void resolveArgumentInvalidContentType() throws Exception { this.servletRequest.setContentType("bad"); servletRequest.setContent("payload".getBytes(StandardCharsets.UTF_8)); processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null); }
@Override protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { super.validateIfApplicable(binder, interfaceMethodParameter(methodParam, Valid.class)); } });
/** * Return the list of return value handlers to use including built-in and * custom handlers provided via {@link #setReturnValueHandlers}. */ protected List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers() { List<HandlerMethodReturnValueHandler> handlers = new ArrayList<>(); // Single-purpose return value types handlers.add(new ModelAndViewMethodReturnValueHandler()); handlers.add(new ModelMethodProcessor()); handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new HttpEntityMethodProcessor( getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice)); // Annotation-based return value types handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new RequestResponseBodyMethodProcessor( getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice)); // Multi-purpose return value types handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new MapMethodProcessor()); // Custom return value types if (getCustomReturnValueHandlers() != null) { handlers.addAll(getCustomReturnValueHandlers()); } // Catch-all handlers.add(new ModelAttributeMethodProcessor(true)); return handlers; }
@Test // SPR-13423 public void handleReturnValueCharSequence() throws Exception { List<HttpMessageConverter<?>>converters = new ArrayList<>(); converters.add(new ByteArrayHttpMessageConverter()); converters.add(new StringHttpMessageConverter()); Method method = ResponseBodyController.class.getMethod("handleWithCharSequence"); MethodParameter returnType = new MethodParameter(method, -1); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); processor.handleReturnValue(new StringBuilder("Foo"), returnType, container, request); assertEquals("text/plain;charset=ISO-8859-1", servletResponse.getHeader("Content-Type")); assertEquals("Foo", servletResponse.getContentAsString()); }
@Override public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException { mavContainer.setRequestHandled(true); ServletServerHttpRequest inputMessage = createInputMessage(webRequest); ServletServerHttpResponse outputMessage = createOutputMessage(webRequest); // Try even with null return value. ResponseBodyAdvice could get involved. writeWithMessageConverters(returnValue, returnType, inputMessage, outputMessage); }
@Test public void supportsReturnTypeRestController() throws Exception { Method method = TestRestController.class.getMethod("handle"); MethodParameter returnType = new MethodParameter(method, -1); List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new StringHttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); assertTrue("Failed to recognize type-level @RestController", processor.supportsReturnType(returnType)); }
@Override protected <T> Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter parameter, Type paramType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException { HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); Assert.state(servletRequest != null, "No HttpServletRequest"); ServletServerHttpRequest inputMessage = new ServletServerHttpRequest(servletRequest); Object arg = readWithMessageConverters(inputMessage, parameter, paramType); if (arg == null && checkRequired(parameter)) { throw new HttpMessageNotReadableException("Required request body is missing: " + parameter.getExecutable().toGenericString(), inputMessage); } return arg; }
@Test(expected = HttpMediaTypeNotSupportedException.class) public void resolveArgumentNoContentType() throws Exception { servletRequest.setContent("payload".getBytes(StandardCharsets.UTF_8)); given(stringMessageConverter.canRead(String.class, MediaType.APPLICATION_OCTET_STREAM)).willReturn(false); processor.resolveArgument(paramRequestBodyString, mavContainer, webRequest, null); }
@Test public void resolveArgumentClassJson() throws Exception { String content = "{\"name\" : \"Jad\"}"; this.servletRequest.setContent(content.getBytes("UTF-8")); this.servletRequest.setContentType("application/json"); List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); SimpleBean result = (SimpleBean) processor.resolveArgument( paramSimpleBean, container, request, factory); assertNotNull(result); assertEquals("Jad", result.getName()); }
handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters(), this.contentNegotiationManager, this.requestResponseBodyAdvice));
@Test // SPR-13631 public void defaultCharset() throws Exception { Method method = JacksonController.class.getMethod("defaultCharset"); HandlerMethod handlerMethod = new HandlerMethod(new JacksonController(), method); MethodParameter methodReturnType = handlerMethod.getReturnType(); List<HttpMessageConverter<?>> converters = new ArrayList<>(); converters.add(new MappingJackson2HttpMessageConverter()); RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters); Object returnValue = new JacksonController().defaultCharset(); processor.handleReturnValue(returnValue, methodReturnType, this.container, this.request); assertEquals("UTF-8", this.servletResponse.getCharacterEncoding()); }