/** * Constructor with converters and {@code Request~} and {@code ResponseBodyAdvice}. * @since 4.2 */ public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters, @Nullable List<Object> requestResponseBodyAdvice) { Assert.notEmpty(converters, "'messageConverters' must not be empty"); this.messageConverters = converters; this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters); this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice); }
@SuppressWarnings("unchecked") private <A> List<A> getMatchingAdvice(MethodParameter parameter, Class<? extends A> adviceType) { List<Object> availableAdvice = getAdvice(adviceType); if (CollectionUtils.isEmpty(availableAdvice)) { return Collections.emptyList(); } List<A> result = new ArrayList<>(availableAdvice.size()); for (Object advice : availableAdvice) { if (advice instanceof ControllerAdviceBean) { ControllerAdviceBean adviceBean = (ControllerAdviceBean) advice; if (!adviceBean.isApplicableToBeanType(parameter.getContainingClass())) { continue; } advice = adviceBean.resolveBean(); } if (adviceType.isAssignableFrom(advice.getClass())) { result.add((A) advice); } } return result; }
@Override @Nullable public Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) { for (RequestBodyAdvice advice : getMatchingAdvice(parameter, RequestBodyAdvice.class)) { if (advice.supports(parameter, targetType, converterType)) { body = advice.handleEmptyBody(body, inputMessage, parameter, targetType, converterType); } } return body; }
if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
@SuppressWarnings("unchecked") @Test public void requestBodyAdvice() throws IOException { RequestBodyAdvice requestAdvice = Mockito.mock(RequestBodyAdvice.class); ResponseBodyAdvice<String> responseAdvice = Mockito.mock(ResponseBodyAdvice.class); List<Object> advice = Arrays.asList(requestAdvice, responseAdvice); RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(advice); HttpInputMessage wrapped = new ServletServerHttpRequest(new MockHttpServletRequest()); given(requestAdvice.supports(this.paramType, String.class, this.converterType)).willReturn(true); given(requestAdvice.beforeBodyRead(eq(this.request), eq(this.paramType), eq(String.class), eq(this.converterType))).willReturn(wrapped); assertSame(wrapped, chain.beforeBodyRead(this.request, this.paramType, String.class, this.converterType)); String modified = "body++"; given(requestAdvice.afterBodyRead(eq(this.body), eq(this.request), eq(this.paramType), eq(String.class), eq(this.converterType))).willReturn(modified); assertEquals(modified, chain.afterBodyRead(this.body, this.request, this.paramType, String.class, this.converterType)); }
@Test public void controllerAdvice() { Object adviceBean = new ControllerAdviceBean(new MyControllerAdvice()); RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(Collections.singletonList(adviceBean)); String actual = (String) chain.beforeBodyWrite(this.body, this.returnType, this.contentType, this.converterType, this.request, this.response); assertEquals("body-MyControllerAdvice", actual); }
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage);
@Override @Nullable public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) { return processBody(body, returnType, contentType, converterType, request, response); }
/** * Create an instance from a list of objects that are either of type * {@code ControllerAdviceBean} or {@code RequestBodyAdvice}. */ public RequestResponseBodyAdviceChain(@Nullable List<Object> requestResponseBodyAdvice) { this.requestBodyAdvice.addAll(getAdviceByType(requestResponseBodyAdvice, RequestBodyAdvice.class)); this.responseBodyAdvice.addAll(getAdviceByType(requestResponseBodyAdvice, ResponseBodyAdvice.class)); }
if (message.hasBody()) { HttpInputMessage msgToUse = getAdvice().beforeBodyRead(message, parameter, targetType, converterType); body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) : ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse)); body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType); body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
@Test public void controllerAdviceNotApplicable() { Object adviceBean = new ControllerAdviceBean(new TargetedControllerAdvice()); RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(Collections.singletonList(adviceBean)); String actual = (String) chain.beforeBodyWrite(this.body, this.returnType, this.contentType, this.converterType, this.request, this.response); assertEquals(this.body, actual); }
((GenericHttpMessageConverter) converter).canWrite(targetType, valueType, selectedMediaType) : converter.canWrite(valueType, selectedMediaType)) { body = getAdvice().beforeBodyWrite(body, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) converter.getClass(), inputMessage, outputMessage);
@Override @Nullable public Object beforeBodyWrite(@Nullable Object body, MethodParameter returnType, MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) { return processBody(body, returnType, contentType, converterType, request, response); }
private int getBodyAdviceCount(Class<?> adviceType) { List<Object> advice = this.requestResponseBodyAdvice; return RequestBodyAdvice.class.isAssignableFrom(adviceType) ? RequestResponseBodyAdviceChain.getAdviceByType(advice, RequestBodyAdvice.class).size() : RequestResponseBodyAdviceChain.getAdviceByType(advice, ResponseBodyAdvice.class).size(); }
inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType); body = genericConverter.read(targetType, contextClass, inputMessage); body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType); body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType); inputMessage = getAdvice().beforeBodyRead(inputMessage, parameter, targetType, converterType); body = ((HttpMessageConverter<T>) converter).read(targetClass, inputMessage); body = getAdvice().afterBodyRead(body, inputMessage, parameter, targetType, converterType); body = getAdvice().handleEmptyBody(null, inputMessage, parameter, targetType, converterType);
@SuppressWarnings("unchecked") @Test public void responseBodyAdvice() { RequestBodyAdvice requestAdvice = Mockito.mock(RequestBodyAdvice.class); ResponseBodyAdvice<String> responseAdvice = Mockito.mock(ResponseBodyAdvice.class); List<Object> advice = Arrays.asList(requestAdvice, responseAdvice); RequestResponseBodyAdviceChain chain = new RequestResponseBodyAdviceChain(advice); String expected = "body++"; given(responseAdvice.supports(this.returnType, this.converterType)).willReturn(true); given(responseAdvice.beforeBodyWrite(eq(this.body), eq(this.returnType), eq(this.contentType), eq(this.converterType), same(this.request), same(this.response))).willReturn(expected); String actual = (String) chain.beforeBodyWrite(this.body, this.returnType, this.contentType, this.converterType, this.request, this.response); assertEquals(expected, actual); }
@SuppressWarnings("unchecked") @Nullable private <T> Object processBody(@Nullable Object body, MethodParameter returnType, MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) { for (ResponseBodyAdvice<?> advice : getMatchingAdvice(returnType, ResponseBodyAdvice.class)) { if (advice.supports(returnType, converterType)) { body = ((ResponseBodyAdvice<T>) advice).beforeBodyWrite((T) body, returnType, contentType, converterType, request, response); } } return body; }
/** * Constructor with converters and {@code Request~} and {@code ResponseBodyAdvice}. * @since 4.2 */ public AbstractMessageConverterMethodArgumentResolver(List<HttpMessageConverter<?>> converters, @Nullable List<Object> requestResponseBodyAdvice) { Assert.notEmpty(converters, "'messageConverters' must not be empty"); this.messageConverters = converters; this.allSupportedMediaTypes = getAllSupportedMediaTypes(converters); this.advice = new RequestResponseBodyAdviceChain(requestResponseBodyAdvice); }
if (((GenericHttpMessageConverter) messageConverter).canWrite( declaredType, valueType, selectedMediaType)) { outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType, (Class<? extends HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
@Override public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType contentType, Class<? extends HttpMessageConverter<?>> converterType, ServerHttpRequest request, ServerHttpResponse response) { return processBody(body, returnType, contentType, converterType, request, response); }