Rename ResponseBodyInterceptor to ResponseBodyAdvice

Issue: SPR-10859
This commit is contained in:
Rossen Stoyanchev 2014-05-30 17:01:28 -04:00
parent 2655c507e0
commit c9d0ebd730
17 changed files with 123 additions and 121 deletions

View File

@ -19,7 +19,7 @@ package org.springframework.web.servlet.config;
import java.util.List; import java.util.List;
import java.util.Properties; import java.util.Properties;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
import org.springframework.http.converter.json.GsonHttpMessageConverter; import org.springframework.http.converter.json.GsonHttpMessageConverter;
import org.w3c.dom.Element; import org.w3c.dom.Element;
@ -201,7 +201,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); handlerAdapterDef.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef); handlerAdapterDef.getPropertyValues().add("webBindingInitializer", bindingDef);
handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters); handlerAdapterDef.getPropertyValues().add("messageConverters", messageConverters);
addResponseBodyInterceptors(handlerAdapterDef); addResponseBodyAdvice(handlerAdapterDef);
if (element.hasAttribute("ignore-default-model-on-redirect")) { if (element.hasAttribute("ignore-default-model-on-redirect")) {
Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect")); Boolean ignoreDefaultModel = Boolean.valueOf(element.getAttribute("ignore-default-model-on-redirect"));
@ -253,7 +253,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager); exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0); exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyInterceptors(exceptionHandlerExceptionResolver); addResponseBodyAdvice(exceptionHandlerExceptionResolver);
String methodExceptionResolverName = String methodExceptionResolverName =
parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver); parserContext.getReaderContext().registerWithGeneratedName(exceptionHandlerExceptionResolver);
@ -288,10 +288,10 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return null; return null;
} }
protected void addResponseBodyInterceptors(RootBeanDefinition beanDef) { protected void addResponseBodyAdvice(RootBeanDefinition beanDef) {
if (jackson2Present) { if (jackson2Present) {
beanDef.getPropertyValues().add("responseBodyInterceptors", beanDef.getPropertyValues().add("responseBodyAdvice",
new RootBeanDefinition(JsonViewResponseBodyInterceptor.class)); new RootBeanDefinition(JsonViewResponseBodyAdvice.class));
} }
} }

View File

@ -17,7 +17,6 @@
package org.springframework.web.servlet.config.annotation; package org.springframework.web.servlet.config.annotation;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -76,10 +75,10 @@ import org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter;
import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter; import org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.servlet.resource.ResourceUrlProvider; import org.springframework.web.servlet.resource.ResourceUrlProvider;
import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor; import org.springframework.web.servlet.resource.ResourceUrlProviderExposingInterceptor;
@ -425,9 +424,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
adapter.setCustomReturnValueHandlers(returnValueHandlers); adapter.setCustomReturnValueHandlers(returnValueHandlers);
if (jackson2Present) { if (jackson2Present) {
List<ResponseBodyInterceptor<?>> interceptors = new ArrayList<ResponseBodyInterceptor<?>>(); List<ResponseBodyAdvice<?>> interceptors = new ArrayList<ResponseBodyAdvice<?>>();
interceptors.add(new JsonViewResponseBodyInterceptor()); interceptors.add(new JsonViewResponseBodyAdvice());
adapter.setResponseBodyInterceptors(interceptors); adapter.setResponseBodyAdvice(interceptors);
} }
AsyncSupportConfigurer configurer = new AsyncSupportConfigurer(); AsyncSupportConfigurer configurer = new AsyncSupportConfigurer();
@ -712,9 +711,9 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
exceptionHandlerExceptionResolver.setContentNegotiationManager(mvcContentNegotiationManager()); exceptionHandlerExceptionResolver.setContentNegotiationManager(mvcContentNegotiationManager());
exceptionHandlerExceptionResolver.setMessageConverters(getMessageConverters()); exceptionHandlerExceptionResolver.setMessageConverters(getMessageConverters());
if (jackson2Present) { if (jackson2Present) {
List<ResponseBodyInterceptor<?>> interceptors = new ArrayList<ResponseBodyInterceptor<?>>(); List<ResponseBodyAdvice<?>> interceptors = new ArrayList<ResponseBodyAdvice<?>>();
interceptors.add(new JsonViewResponseBodyInterceptor()); interceptors.add(new JsonViewResponseBodyAdvice());
exceptionHandlerExceptionResolver.setResponseBodyInterceptors(interceptors); exceptionHandlerExceptionResolver.setResponseBodyAdvice(interceptors);
} }
exceptionHandlerExceptionResolver.afterPropertiesSet(); exceptionHandlerExceptionResolver.afterPropertiesSet();

View File

@ -29,7 +29,7 @@ import javax.servlet.http.HttpServletRequest;
import java.util.Collection; import java.util.Collection;
/** /**
* A convenient base class for a {@code ResponseBodyInterceptor} to instruct the * A convenient base class for a {@code ResponseBodyAdvice} to instruct the
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter * {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
* MappingJackson2HttpMessageConverter} to serialize with JSONP formatting. * MappingJackson2HttpMessageConverter} to serialize with JSONP formatting.
* *
@ -43,12 +43,12 @@ import java.util.Collection;
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
*/ */
public abstract class AbstractJsonpResponseBodyInterceptor extends AbstractMappingJacksonResponseBodyInterceptor { public abstract class AbstractJsonpResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {
private final String[] jsonpQueryParamNames; private final String[] jsonpQueryParamNames;
protected AbstractJsonpResponseBodyInterceptor(Collection<String> queryParamNames) { protected AbstractJsonpResponseBodyAdvice(Collection<String> queryParamNames) {
Assert.isTrue(!CollectionUtils.isEmpty(queryParamNames), "At least one query param name is required"); Assert.isTrue(!CollectionUtils.isEmpty(queryParamNames), "At least one query param name is required");
this.jsonpQueryParamNames = queryParamNames.toArray(new String[queryParamNames.size()]); this.jsonpQueryParamNames = queryParamNames.toArray(new String[queryParamNames.size()]);
} }

View File

@ -25,7 +25,7 @@ import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse; import org.springframework.http.server.ServerHttpResponse;
/** /**
* A convenient base class for {@code ResponseBodyInterceptor} implementations * A convenient base class for {@code ResponseBodyAdvice} implementations
* that customize the response before JSON serialization with * that customize the response before JSON serialization with
* {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter * {@link org.springframework.http.converter.json.MappingJackson2HttpMessageConverter
* MappingJackson2HttpMessageConverter}. * MappingJackson2HttpMessageConverter}.
@ -33,11 +33,11 @@ import org.springframework.http.server.ServerHttpResponse;
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
*/ */
public abstract class AbstractMappingJacksonResponseBodyInterceptor public abstract class AbstractMappingJacksonResponseBodyAdvice
implements ResponseBodyInterceptor<Object> { implements ResponseBodyAdvice<Object> {
protected AbstractMappingJacksonResponseBodyInterceptor() { protected AbstractMappingJacksonResponseBodyAdvice() {
} }

View File

@ -31,7 +31,6 @@ import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter; import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest; import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse; import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.ClassUtils;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException; import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.accept.ContentNegotiationManager; import org.springframework.web.accept.ContentNegotiationManager;
@ -55,7 +54,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
private final ContentNegotiationManager contentNegotiationManager; private final ContentNegotiationManager contentNegotiationManager;
private final ResponseBodyInterceptorChain interceptorChain; private final ResponseBodyAdviceChain adviceChain;
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) { protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) {
@ -68,11 +67,11 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
} }
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters, protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters,
ContentNegotiationManager manager, List<Object> responseBodyInterceptors) { ContentNegotiationManager manager, List<Object> responseBodyAdvice) {
super(messageConverters); super(messageConverters);
this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager()); this.contentNegotiationManager = (manager != null ? manager : new ContentNegotiationManager());
this.interceptorChain = new ResponseBodyInterceptorChain(responseBodyInterceptors); this.adviceChain = new ResponseBodyAdviceChain(responseBodyAdvice);
} }
@ -149,7 +148,7 @@ public abstract class AbstractMessageConverterMethodProcessor extends AbstractMe
selectedMediaType = selectedMediaType.removeQualityValue(); selectedMediaType = selectedMediaType.removeQualityValue();
for (HttpMessageConverter<?> messageConverter : this.messageConverters) { for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter.canWrite(returnValueClass, selectedMediaType)) { if (messageConverter.canWrite(returnValueClass, selectedMediaType)) {
returnValue = this.interceptorChain.invoke(returnValue, returnType, selectedMediaType, returnValue = this.adviceChain.invoke(returnValue, returnType, selectedMediaType,
(Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage); (Class<HttpMessageConverter<?>>) messageConverter.getClass(), inputMessage, outputMessage);
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage); ((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {

View File

@ -79,7 +79,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager();
private final List<Object> responseBodyInterceptors = new ArrayList<Object>(); private final List<Object> responseBodyAdvice = new ArrayList<Object>();
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache =
@ -110,15 +110,15 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
} }
/** /**
* Add one or more interceptors to be invoked after the execution of a controller * Add one or more components to be invoked after the execution of a controller
* method annotated with {@code @ResponseBody} or returning {@code ResponseEntity} * method annotated with {@code @ResponseBody} or returning {@code ResponseEntity}
* but before the body is written to the response with the selected * but before the body is written to the response with the selected
* {@code HttpMessageConverter}. * {@code HttpMessageConverter}.
*/ */
public void setResponseBodyInterceptors(List<ResponseBodyInterceptor<?>> responseBodyInterceptors) { public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) {
this.responseBodyInterceptors.clear(); this.responseBodyAdvice.clear();
if (responseBodyInterceptors != null) { if (responseBodyAdvice != null) {
this.responseBodyInterceptors.addAll(responseBodyInterceptors); this.responseBodyAdvice.addAll(responseBodyAdvice);
} }
} }
@ -250,7 +250,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
// Do this first, it may add ResponseBody interceptors // Do this first, it may add ResponseBodyAdvice beans
initExceptionHandlerAdviceCache(); initExceptionHandlerAdviceCache();
if (this.argumentResolvers == null) { if (this.argumentResolvers == null) {
@ -271,18 +271,18 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
logger.debug("Looking for exception mappings: " + getApplicationContext()); logger.debug("Looking for exception mappings: " + getApplicationContext());
} }
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); List<ControllerAdviceBean> adviceBeans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
Collections.sort(beans, new OrderComparator()); Collections.sort(adviceBeans, new OrderComparator());
for (ControllerAdviceBean bean : beans) { for (ControllerAdviceBean adviceBean : adviceBeans) {
ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(bean.getBeanType()); ExceptionHandlerMethodResolver resolver = new ExceptionHandlerMethodResolver(adviceBean.getBeanType());
if (resolver.hasExceptionMappings()) { if (resolver.hasExceptionMappings()) {
this.exceptionHandlerAdviceCache.put(bean, resolver); this.exceptionHandlerAdviceCache.put(adviceBean, resolver);
logger.info("Detected @ExceptionHandler methods in " + bean); logger.info("Detected @ExceptionHandler methods in " + adviceBean);
} }
if (ResponseBodyInterceptor.class.isAssignableFrom(bean.getBeanType())) { if (ResponseBodyAdvice.class.isAssignableFrom(adviceBean.getBeanType())) {
this.responseBodyInterceptors.add(bean); this.responseBodyAdvice.add(adviceBean);
logger.info("Detected ResponseBodyInterceptor implementation in " + bean); logger.info("Detected ResponseBodyAdvice implementation in " + adviceBean);
} }
} }
} }
@ -318,12 +318,12 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce
handlers.add(new ModelMethodProcessor()); handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor( handlers.add(new HttpEntityMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyInterceptors)); getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
// Annotation-based return value types // Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor( handlers.add(new RequestResponseBodyMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyInterceptors)); getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
// Multi-purpose return value types // Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new ViewNameMethodReturnValueHandler());

View File

@ -61,8 +61,8 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
} }
public HttpEntityMethodProcessor(List<HttpMessageConverter<?>> messageConverters, public HttpEntityMethodProcessor(List<HttpMessageConverter<?>> messageConverters,
ContentNegotiationManager contentNegotiationManager, List<Object> responseBodyInterceptors) { ContentNegotiationManager contentNegotiationManager, List<Object> responseBodyAdvice) {
super(messageConverters, contentNegotiationManager, responseBodyInterceptors); super(messageConverters, contentNegotiationManager, responseBodyAdvice);
} }

View File

@ -26,7 +26,7 @@ import org.springframework.http.server.ServerHttpResponse;
import org.springframework.util.Assert; import org.springframework.util.Assert;
/** /**
* A {@code ResponseBodyInterceptor} implementation that adds support for * A {@code ResponseBodyAdvice} implementation that adds support for
* Jackson's {@code @JsonView} annotation declared on a Spring MVC * Jackson's {@code @JsonView} annotation declared on a Spring MVC
* {@code @RequestMapping} or {@code @ExceptionHandler} method. The serialization * {@code @RequestMapping} or {@code @ExceptionHandler} method. The serialization
* view specified in the annotation will be passed in to the * view specified in the annotation will be passed in to the
@ -38,7 +38,7 @@ import org.springframework.util.Assert;
* *
* @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class) * @see com.fasterxml.jackson.databind.ObjectMapper#writerWithView(Class)
*/ */
public class JsonViewResponseBodyInterceptor extends AbstractMappingJacksonResponseBodyInterceptor { public class JsonViewResponseBodyAdvice extends AbstractMappingJacksonResponseBodyAdvice {
@Override @Override

View File

@ -132,7 +132,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
private List<HttpMessageConverter<?>> messageConverters; private List<HttpMessageConverter<?>> messageConverters;
private List<Object> responseBodyInterceptors = new ArrayList<Object>(); private List<Object> responseBodyAdvice = new ArrayList<Object>();
private WebBindingInitializer webBindingInitializer; private WebBindingInitializer webBindingInitializer;
@ -334,15 +334,15 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
} }
/** /**
* Add one or more interceptors to be invoked after the execution of a controller * Add one or more components to modify the response after the execution of a
* method annotated with {@code @ResponseBody} or returning {@code ResponseEntity} * controller method annotated with {@code @ResponseBody}, or a method returning
* but before the body is written to the response with the selected * {@code ResponseEntity} and before the body is written to the response with
* {@code HttpMessageConverter}. * the selected {@code HttpMessageConverter}.
*/ */
public void setResponseBodyInterceptors(List<ResponseBodyInterceptor<?>> responseBodyInterceptors) { public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) {
this.responseBodyInterceptors.clear(); this.responseBodyAdvice.clear();
if (responseBodyInterceptors != null) { if (responseBodyAdvice != null) {
this.responseBodyInterceptors.addAll(responseBodyInterceptors); this.responseBodyAdvice.addAll(responseBodyAdvice);
} }
} }
@ -498,7 +498,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
@Override @Override
public void afterPropertiesSet() { public void afterPropertiesSet() {
// Do this first, it may add ResponseBody interceptors // Do this first, it may add ResponseBody advice beans
initControllerAdviceCache(); initControllerAdviceCache();
if (this.argumentResolvers == null) { if (this.argumentResolvers == null) {
@ -526,7 +526,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext()); List<ControllerAdviceBean> beans = ControllerAdviceBean.findAnnotatedBeans(getApplicationContext());
Collections.sort(beans, new OrderComparator()); Collections.sort(beans, new OrderComparator());
List<Object> interceptorBeans = new ArrayList<Object>(); List<Object> responseBodyAdviceBeans = new ArrayList<Object>();
for (ControllerAdviceBean bean : beans) { for (ControllerAdviceBean bean : beans) {
Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS); Set<Method> attrMethods = HandlerMethodSelector.selectMethods(bean.getBeanType(), MODEL_ATTRIBUTE_METHODS);
@ -539,14 +539,14 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
this.initBinderAdviceCache.put(bean, binderMethods); this.initBinderAdviceCache.put(bean, binderMethods);
logger.info("Detected @InitBinder methods in " + bean); logger.info("Detected @InitBinder methods in " + bean);
} }
if (ResponseBodyInterceptor.class.isAssignableFrom(bean.getBeanType())) { if (ResponseBodyAdvice.class.isAssignableFrom(bean.getBeanType())) {
interceptorBeans.add(bean); responseBodyAdviceBeans.add(bean);
logger.info("Detected ResponseBodyInterceptor implementation in " + bean); logger.info("Detected ResponseBodyAdvice bean in " + bean);
} }
} }
if (!interceptorBeans.isEmpty()) { if (!responseBodyAdviceBeans.isEmpty()) {
this.responseBodyInterceptors.addAll(0, interceptorBeans); this.responseBodyAdvice.addAll(0, responseBodyAdviceBeans);
} }
} }
@ -638,7 +638,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
handlers.add(new ModelMethodProcessor()); handlers.add(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler()); handlers.add(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor( handlers.add(new HttpEntityMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyInterceptors)); getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
handlers.add(new HttpHeadersReturnValueHandler()); handlers.add(new HttpHeadersReturnValueHandler());
handlers.add(new CallableMethodReturnValueHandler()); handlers.add(new CallableMethodReturnValueHandler());
handlers.add(new DeferredResultMethodReturnValueHandler()); handlers.add(new DeferredResultMethodReturnValueHandler());
@ -648,7 +648,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
// Annotation-based return value types // Annotation-based return value types
handlers.add(new ModelAttributeMethodProcessor(false)); handlers.add(new ModelAttributeMethodProcessor(false));
handlers.add(new RequestResponseBodyMethodProcessor( handlers.add(new RequestResponseBodyMethodProcessor(
getMessageConverters(), this.contentNegotiationManager, this.responseBodyInterceptors)); getMessageConverters(), this.contentNegotiationManager, this.responseBodyAdvice));
// Multi-purpose return value types // Multi-purpose return value types
handlers.add(new ViewNameMethodReturnValueHandler()); handlers.add(new ViewNameMethodReturnValueHandler());

View File

@ -73,8 +73,8 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
} }
public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> messageConverters, public RequestResponseBodyMethodProcessor(List<HttpMessageConverter<?>> messageConverters,
ContentNegotiationManager contentNegotiationManager, List<Object> responseBodyInterceptors) { ContentNegotiationManager contentNegotiationManager, List<Object> responseBodyAdvice) {
super(messageConverters, contentNegotiationManager, responseBodyInterceptors); super(messageConverters, contentNegotiationManager, responseBodyAdvice);
} }

View File

@ -27,13 +27,18 @@ import org.springframework.http.server.ServerHttpResponse;
* or an {@code ResponseEntity} controller method but before the body is written * or an {@code ResponseEntity} controller method but before the body is written
* with an {@code HttpMessageConverter}. * with an {@code HttpMessageConverter}.
* *
* <p>Implementations may be may be registered directly with
* {@code RequestMappingHandlerAdapter} and {@code ExceptionHandlerExceptionResolver}
* or more likely annotated with {@code @ControllerAdvice} in which case they
* will be auto-detected by both.
*
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
*/ */
public interface ResponseBodyInterceptor<T> { public interface ResponseBodyAdvice<T> {
/** /**
* Whether this interceptor supports the given controller method return type * Whether this component supports the given controller method return type
* and the selected {@code HttpMessageConverter} type. * and the selected {@code HttpMessageConverter} type.
* *
* @param returnType the return type * @param returnType the return type

View File

@ -28,20 +28,20 @@ import org.springframework.web.method.ControllerAdviceBean;
import java.util.List; import java.util.List;
/** /**
* Invokes a a list of ResponseBodyInterceptor's. * Invokes a a list of {@link ResponseBodyAdvice} beans.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
*/ */
class ResponseBodyInterceptorChain { class ResponseBodyAdviceChain {
private static Log logger = LogFactory.getLog(ResponseBodyInterceptorChain.class); private static Log logger = LogFactory.getLog(ResponseBodyAdviceChain.class);
private final List<Object> interceptors; private final List<Object> advice;
public ResponseBodyInterceptorChain(List<Object> interceptors) { public ResponseBodyAdviceChain(List<Object> advice) {
this.interceptors = interceptors; this.advice = advice;
} }
@ -50,31 +50,31 @@ class ResponseBodyInterceptorChain {
MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType,
ServerHttpRequest request, ServerHttpResponse response) { ServerHttpRequest request, ServerHttpResponse response) {
if (this.interceptors != null) { if (this.advice != null) {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Invoking ResponseBody interceptor chain for body=" + body); logger.debug("Invoking ResponseBodyAdvice chain for body=" + body);
} }
for (Object interceptor : this.interceptors) { for (Object advice : this.advice) {
if (interceptor instanceof ControllerAdviceBean) { if (advice instanceof ControllerAdviceBean) {
ControllerAdviceBean adviceBean = (ControllerAdviceBean) interceptor; ControllerAdviceBean adviceBean = (ControllerAdviceBean) advice;
if (!adviceBean.isApplicableToBeanType(returnType.getContainingClass())) { if (!adviceBean.isApplicableToBeanType(returnType.getContainingClass())) {
continue; continue;
} }
interceptor = adviceBean.resolveBean(); advice = adviceBean.resolveBean();
} }
if (interceptor instanceof ResponseBodyInterceptor) { if (advice instanceof ResponseBodyAdvice) {
ResponseBodyInterceptor<T> typedInterceptor = (ResponseBodyInterceptor<T>) interceptor; ResponseBodyAdvice<T> typedAdvice = (ResponseBodyAdvice<T>) advice;
if (typedInterceptor.supports(returnType, selectedConverterType)) { if (typedAdvice.supports(returnType, selectedConverterType)) {
body = typedInterceptor.beforeBodyWrite(body, returnType, body = typedAdvice.beforeBodyWrite(body, returnType,
selectedContentType, selectedConverterType, request, response); selectedContentType, selectedConverterType, request, response);
} }
} }
else { else {
throw new IllegalStateException("Expected a ResponseBodyInterceptor: " + interceptor); throw new IllegalStateException("Expected ResponseBodyAdvice: " + advice);
} }
} }
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("After interceptor chain body=" + body); logger.debug("After ResponseBodyAdvice chain body=" + body);
} }
} }
return body; return body;

View File

@ -38,11 +38,11 @@ import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler; import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping; import org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter; import org.springframework.web.servlet.mvc.method.annotation.ServletWebArgumentResolverAdapter;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
@ -95,8 +95,8 @@ public class AnnotationDrivenBeanDefinitionParserTests {
loadBeanDefinitions("mvc-config-message-converters.xml"); loadBeanDefinitions("mvc-config-message-converters.xml");
verifyMessageConverters(appContext.getBean(RequestMappingHandlerAdapter.class), true); verifyMessageConverters(appContext.getBean(RequestMappingHandlerAdapter.class), true);
verifyMessageConverters(appContext.getBean(ExceptionHandlerExceptionResolver.class), true); verifyMessageConverters(appContext.getBean(ExceptionHandlerExceptionResolver.class), true);
verifyResponseBodyInterceptors(appContext.getBean(RequestMappingHandlerAdapter.class)); verifyResponseBodyAdvice(appContext.getBean(RequestMappingHandlerAdapter.class));
verifyResponseBodyInterceptors(appContext.getBean(ExceptionHandlerExceptionResolver.class)); verifyResponseBodyAdvice(appContext.getBean(ExceptionHandlerExceptionResolver.class));
} }
@Test @Test
@ -167,13 +167,13 @@ public class AnnotationDrivenBeanDefinitionParserTests {
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
private void verifyResponseBodyInterceptors(Object bean) { private void verifyResponseBodyAdvice(Object bean) {
assertNotNull(bean); assertNotNull(bean);
Object value = new DirectFieldAccessor(bean).getPropertyValue("responseBodyInterceptors"); Object value = new DirectFieldAccessor(bean).getPropertyValue("responseBodyAdvice");
assertNotNull(value); assertNotNull(value);
assertTrue(value instanceof List); assertTrue(value instanceof List);
List<ResponseBodyInterceptor> converters = (List<ResponseBodyInterceptor>) value; List<ResponseBodyAdvice> converters = (List<ResponseBodyAdvice>) value;
assertTrue(converters.get(0) instanceof JsonViewResponseBodyInterceptor); assertTrue(converters.get(0) instanceof JsonViewResponseBodyAdvice);
} }
} }

View File

@ -52,7 +52,7 @@ import org.springframework.web.servlet.handler.ConversionServiceExposingIntercep
import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite; import org.springframework.web.servlet.handler.HandlerExceptionResolverComposite;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyInterceptor; import org.springframework.web.servlet.mvc.method.annotation.JsonViewResponseBodyAdvice;
import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder; import org.springframework.web.servlet.mvc.method.annotation.MvcUriComponentsBuilder;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
@ -161,9 +161,9 @@ public class WebMvcConfigurationSupportTests {
assertTrue(validator instanceof LocalValidatorFactoryBean); assertTrue(validator instanceof LocalValidatorFactoryBean);
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter); DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(adapter);
List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyInterceptors"); List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyAdvice");
assertEquals(1, interceptors.size()); assertEquals(1, interceptors.size());
assertEquals(JsonViewResponseBodyInterceptor.class, interceptors.get(0).getClass()); assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass());
} }
@Test @Test
@ -192,9 +192,9 @@ public class WebMvcConfigurationSupportTests {
assertNotNull(eher.getApplicationContext()); assertNotNull(eher.getApplicationContext());
DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(eher); DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(eher);
List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyInterceptors"); List<Object> interceptors = (List<Object>) fieldAccessor.getPropertyValue("responseBodyAdvice");
assertEquals(1, interceptors.size()); assertEquals(1, interceptors.size());
assertEquals(JsonViewResponseBodyInterceptor.class, interceptors.get(0).getClass()); assertEquals(JsonViewResponseBodyAdvice.class, interceptors.get(0).getClass());
} }

View File

@ -19,7 +19,6 @@ package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -235,7 +234,7 @@ public class RequestMappingHandlerAdapterTests {
// SPR-10859 // SPR-10859
@Test @Test
public void responseBodyInterceptor() 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());
this.handlerAdapter.setMessageConverters(converters); this.handlerAdapter.setMessageConverters(converters);
@ -339,7 +338,7 @@ public class RequestMappingHandlerAdapterTests {
} }
@ControllerAdvice @ControllerAdvice
private static class ResponseCodeSuppressingAdvice extends AbstractMappingJacksonResponseBodyInterceptor { private static class ResponseCodeSuppressingAdvice extends AbstractMappingJacksonResponseBodyAdvice {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@ -357,7 +356,7 @@ public class RequestMappingHandlerAdapterTests {
} }
@ControllerAdvice @ControllerAdvice
private static class JsonpAdvice extends AbstractJsonpResponseBodyInterceptor { private static class JsonpAdvice extends AbstractJsonpResponseBodyAdvice {
public JsonpAdvice() { public JsonpAdvice() {
super(Arrays.asList("c")); super(Arrays.asList("c"));

View File

@ -299,7 +299,7 @@ public class RequestResponseBodyMethodProcessorTests {
converters.add(new MappingJackson2HttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter());
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor( RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(
converters, null, Arrays.asList(new JsonViewResponseBodyInterceptor())); converters, null, Arrays.asList(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonViewController().handleResponseBody(); Object returnValue = new JacksonViewController().handleResponseBody();
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest); processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);
@ -320,7 +320,7 @@ public class RequestResponseBodyMethodProcessorTests {
converters.add(new MappingJackson2HttpMessageConverter()); converters.add(new MappingJackson2HttpMessageConverter());
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor( HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(
converters, null, Arrays.asList(new JsonViewResponseBodyInterceptor())); converters, null, Arrays.asList(new JsonViewResponseBodyAdvice()));
Object returnValue = new JacksonViewController().handleResponseEntity(); Object returnValue = new JacksonViewController().handleResponseEntity();
processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest); processor.handleReturnValue(returnValue, methodReturnType, this.mavContainer, this.webRequest);

View File

@ -42,12 +42,12 @@ import static org.mockito.Mockito.*;
/** /**
* Unit tests for * Unit tests for
* {@link org.springframework.web.servlet.mvc.method.annotation.ResponseBodyInterceptorChain}. * {@link ResponseBodyAdviceChain}.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 4.1 * @since 4.1
*/ */
public class ResponseBodyInterceptorChainTests { public class ResponseBodyAdviceChainTests {
private String body; private String body;
@ -73,15 +73,15 @@ public class ResponseBodyInterceptorChainTests {
} }
@Test @Test
public void responseBodyInterceptor() { public void responseBodyAdvice() {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ResponseBodyInterceptor<String> interceptor = Mockito.mock(ResponseBodyInterceptor.class); ResponseBodyAdvice<String> advice = Mockito.mock(ResponseBodyAdvice.class);
ResponseBodyInterceptorChain chain = new ResponseBodyInterceptorChain(Arrays.asList(interceptor)); ResponseBodyAdviceChain chain = new ResponseBodyAdviceChain(Arrays.asList(advice));
String expected = "body++"; String expected = "body++";
when(interceptor.supports(this.returnType, this.converterType)).thenReturn(true); when(advice.supports(this.returnType, this.converterType)).thenReturn(true);
when(interceptor.beforeBodyWrite(eq(this.body), eq(this.returnType), eq(this.contentType), when(advice.beforeBodyWrite(eq(this.body), eq(this.returnType), eq(this.contentType),
eq(this.converterType), same(this.request), same(this.response))).thenReturn(expected); eq(this.converterType), same(this.request), same(this.response))).thenReturn(expected);
String actual = chain.invoke(this.body, this.returnType, String actual = chain.invoke(this.body, this.returnType,
@ -93,8 +93,8 @@ public class ResponseBodyInterceptorChainTests {
@Test @Test
public void controllerAdvice() { public void controllerAdvice() {
Object interceptor = new ControllerAdviceBean(new MyControllerAdvice()); Object adviceBean = new ControllerAdviceBean(new MyControllerAdvice());
ResponseBodyInterceptorChain chain = new ResponseBodyInterceptorChain(Arrays.asList(interceptor)); ResponseBodyAdviceChain chain = new ResponseBodyAdviceChain(Arrays.asList(adviceBean));
String actual = chain.invoke(this.body, this.returnType, String actual = chain.invoke(this.body, this.returnType,
this.contentType, this.converterType, this.request, this.response); this.contentType, this.converterType, this.request, this.response);
@ -105,8 +105,8 @@ public class ResponseBodyInterceptorChainTests {
@Test @Test
public void controllerAdviceNotApplicable() { public void controllerAdviceNotApplicable() {
Object interceptor = new ControllerAdviceBean(new TargetedControllerAdvice()); Object adviceBean = new ControllerAdviceBean(new TargetedControllerAdvice());
ResponseBodyInterceptorChain chain = new ResponseBodyInterceptorChain(Arrays.asList(interceptor)); ResponseBodyAdviceChain chain = new ResponseBodyAdviceChain(Arrays.asList(adviceBean));
String actual = chain.invoke(this.body, this.returnType, String actual = chain.invoke(this.body, this.returnType,
this.contentType, this.converterType, this.request, this.response); this.contentType, this.converterType, this.request, this.response);
@ -116,7 +116,7 @@ public class ResponseBodyInterceptorChainTests {
@ControllerAdvice @ControllerAdvice
private static class MyControllerAdvice implements ResponseBodyInterceptor<String> { private static class MyControllerAdvice implements ResponseBodyAdvice<String> {
@Override @Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
@ -134,7 +134,7 @@ public class ResponseBodyInterceptorChainTests {
} }
@ControllerAdvice(annotations = Controller.class) @ControllerAdvice(annotations = Controller.class)
private static class TargetedControllerAdvice implements ResponseBodyInterceptor<String> { private static class TargetedControllerAdvice implements ResponseBodyAdvice<String> {
@Override @Override
public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) { public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {