DefaultHttpEntityMethodProcessor.java
package cn.home1.oss.lib.webmvc.internal;
import static org.springframework.web.HttpMessageConverterUtils.defaultContentNegotiationManager;
import static org.springframework.web.HttpMessageConverterUtils.defaultHttpMessageConverters;
import lombok.Getter;
import lombok.NonNull;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.MethodParameter;
import org.springframework.core.env.PropertyResolver;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMessageConverterUtils;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.FixedContentNegotiationStrategy;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor;
import java.util.List;
/**
* Created by zhanghaolun on 16/8/22.
*/
@Slf4j
public class DefaultHttpEntityMethodProcessor implements HandlerMethodReturnValueHandler, InitializingBean {
/**
* The {@link ContentNegotiationManager} to use to resolve acceptable media types. If not
* provided, the default instance of {@code ContentNegotiationManager} with
* {@link org.springframework.web.accept.HeaderContentNegotiationStrategy
* HeaderContentNegotiationStrategy} and
* {@link org.springframework.web.accept.FixedContentNegotiationStrategy
* FixedContentNegotiationStrategy} (with {@link #setDefaultContentType(MediaType)
* defaultContentType}) will be used.
*/
@Getter
private ContentNegotiationManager contentNegotiationManager;
/**
* The default content type that will be used as a fallback when the requested content type is not
* supported.
*/
@Getter
@Setter
private MediaType defaultContentType;
/**
* The message body converters to use for converting an error message into HTTP response body. If
* not provided, the default converters will be used (see
* {@link HttpMessageConverterUtils#defaultHttpMessageConverters(Object)}
* getDefaultHttpMessageConverters()}).
*/
@NonNull
private List<HttpMessageConverter<?>> messageConverters;
// package visibility for tests
private HandlerMethodReturnValueHandler responseProcessor;
// package visibility for tests
private HandlerMethodReturnValueHandler fallbackResponseProcessor;
@Override
public boolean supportsReturnType(final MethodParameter returnType) {
return this.responseProcessor.supportsReturnType(returnType) || //
this.fallbackResponseProcessor.supportsReturnType(returnType);
}
/**
* handleReturnValue.
*
* @param returnValue must pass a HttpEntity here
* @param returnType returnType
* @param mavContainer mavContainer
* @param webRequest webRequest
* @throws Exception exception
*/
@Override
public void handleReturnValue( //
final Object returnValue, final MethodParameter returnType, //
final ModelAndViewContainer mavContainer, final NativeWebRequest webRequest //
) throws Exception {
try {
this.responseProcessor.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
} catch (final HttpMediaTypeNotAcceptableException ex) {
if (log.isDebugEnabled()) {
log.debug("Requested media type is not supported, falling back to default one", ex);
}
this.fallbackResponseProcessor.handleReturnValue(returnValue, returnType, mavContainer, webRequest);
}
}
@Override
public void afterPropertiesSet() throws Exception {
this.responseProcessor = new HttpEntityMethodProcessor( //
this.messageConverters, //
this.contentNegotiationManager //
);
this.fallbackResponseProcessor = new HttpEntityMethodProcessor( //
this.messageConverters, //
new ContentNegotiationManager( //
new FixedContentNegotiationStrategy(this.defaultContentType) //
) //
);
}
public void setContentNegotiationManager(final ContentNegotiationManager contentNegotiationManager) {
this.contentNegotiationManager = contentNegotiationManager;
}
public List<HttpMessageConverter<?>> getMessageConverters() {
return this.messageConverters;
}
public void setMessageConverters(final List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
public static DefaultHttpEntityMethodProcessor defaultHttpEntityMethodProcessor( //
final PropertyResolver propertyResolver, //
final Object objectMapper //
) {
// before WebMvcAutoConfiguration, cant autowire contentNegotiationManager and httpMessageConverters
// Requested bean is currently in creation: Is there an unresolvable circular reference
final ContentNegotiationManager defaultContentNegotiationManager = defaultContentNegotiationManager();
final List<HttpMessageConverter<?>> defaultHttpMessageConverters = defaultHttpMessageConverters( //
propertyResolver, objectMapper);
final DefaultHttpEntityMethodProcessor processor = new DefaultHttpEntityMethodProcessor();
processor.setContentNegotiationManager(defaultContentNegotiationManager);
processor.setMessageConverters(defaultHttpMessageConverters);
return processor;
}
}