SPR-7353 - @ResponseBody and returned HttpEntity now respect @RequestMapping.produces()

This commit is contained in:
Arjen Poutsma
2011-05-17 09:45:57 +00:00
parent 57c757afc5
commit ad2e0d4587
12 changed files with 396 additions and 219 deletions

View File

@@ -22,7 +22,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@@ -575,7 +574,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* MethodFilter that matches {@link InitBinder @InitBinder} methods.
*/
public static MethodFilter INIT_BINDER_METHODS = new MethodFilter() {
public static final MethodFilter INIT_BINDER_METHODS = new MethodFilter() {
public boolean matches(Method method) {
return AnnotationUtils.findAnnotation(method, InitBinder.class) != null;
@@ -585,7 +584,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* MethodFilter that matches {@link ModelAttribute @ModelAttribute} methods.
*/
public static MethodFilter MODEL_ATTRIBUTE_METHODS = new MethodFilter() {
public static final MethodFilter MODEL_ATTRIBUTE_METHODS = new MethodFilter() {
public boolean matches(Method method) {
return ((AnnotationUtils.findAnnotation(method, RequestMapping.class) == null) &&

View File

@@ -25,6 +25,7 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.core.annotation.AnnotationUtils;
@@ -33,6 +34,9 @@ import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.Assert;
import org.springframework.util.PathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
@@ -46,9 +50,9 @@ import org.springframework.web.servlet.handler.MappedInterceptors;
import org.springframework.web.servlet.mvc.method.condition.RequestConditionFactory;
/**
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo}s for the registration and
* the lookup of {@link HandlerMethod}s.
*
* An {@link AbstractHandlerMethodMapping} variant that uses {@link RequestMappingInfo}s for the registration and the
* lookup of {@link HandlerMethod}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1.0
@@ -84,10 +88,10 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
this.mappedInterceptors = MappedInterceptors.createFromDeclaredBeans(getApplicationContext());
}
}
/**
* {@inheritDoc}
* The handler determination in this method is made based on the presence of a type-level {@link Controller} annotation.
* {@inheritDoc} The handler determination in this method is made based on the presence of a type-level {@link
* Controller} annotation.
*/
@Override
protected boolean isHandler(Class<?> beanType) {
@@ -106,9 +110,8 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
/**
* Provides a {@link RequestMappingInfo} for the given method.
* <p>Only {@link RequestMapping @RequestMapping}-annotated methods are considered.
* Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
* Provides a {@link RequestMappingInfo} for the given method. <p>Only {@link RequestMapping @RequestMapping}-annotated
* methods are considered. Type-level {@link RequestMapping @RequestMapping} annotations are also detected and their
* attributes combined with method-level {@link RequestMapping @RequestMapping} attributes.
*
* @param method the method to create a mapping for
@@ -137,14 +140,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
private static RequestMappingInfo createFromRequestMapping(RequestMapping annotation) {
return new RequestMappingInfo(Arrays.asList(annotation.value()),
RequestConditionFactory.parseMethods(annotation.method()),
RequestConditionFactory.parseParams(annotation.params()),
RequestConditionFactory.parseHeaders(annotation.headers()),
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers())
);
RequestConditionFactory.parseMethods(annotation.method()),
RequestConditionFactory.parseParams(annotation.params()),
RequestConditionFactory.parseHeaders(annotation.headers()),
RequestConditionFactory.parseConsumes(annotation.consumes(), annotation.headers()),
RequestConditionFactory.parseProduces(annotation.produces(), annotation.headers()));
}
@Override
protected Set<String> getMappingPaths(RequestMappingInfo mapping) {
return mapping.getPatterns();
@@ -152,10 +154,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
/**
* Returns a new {@link RequestMappingInfo} with attributes matching to the current request or {@code null}.
*
* @see RequestMappingInfo#getMatchingRequestMapping(String, HttpServletRequest, PathMatcher)
*/
@Override
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
protected RequestMappingInfo getMatchingMapping(RequestMappingInfo mapping,
String lookupPath,
HttpServletRequest request) {
return mapping.getMatchingRequestMapping(lookupPath, request, pathMatcher);
}
@@ -177,26 +182,43 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
/**
* Iterates all {@link RequestMappingInfo}s looking for mappings that match by URL but not by HTTP method.
* @exception HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
*
* @throws HttpRequestMethodNotSupportedException if there are matches by URL but not by HTTP method
*/
@Override
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos, String lookupPath, HttpServletRequest request)
throws HttpRequestMethodNotSupportedException {
protected HandlerMethod handleNoMatch(Set<RequestMappingInfo> requestMappingInfos,
String lookupPath,
HttpServletRequest request) throws ServletException {
Set<String> allowedMethods = new HashSet<String>(6);
Set<MediaType> consumableMediaTypes = new HashSet<MediaType>();
Set<MediaType> producibleMediaTypes = new HashSet<MediaType>();
for (RequestMappingInfo info : requestMappingInfos) {
for (String pattern : info.getPatterns()) {
if (pathMatcher.match(pattern, lookupPath)) {
for (RequestMethod method : info.getMethods().getMethods()) {
allowedMethods.add(method.name());
}
if (!info.getMethods().match(request)) {
for (RequestMethod method : info.getMethods().getMethods()) {
allowedMethods.add(method.name());
}
}
if (!info.getConsumes().match(request)) {
consumableMediaTypes.addAll(info.getConsumes().getMediaTypes());
}
if (!info.getProduces().match(request)) {
producibleMediaTypes.addAll(info.getProduces().getMediaTypes());
}
}
if (!allowedMethods.isEmpty()) {
throw new HttpRequestMethodNotSupportedException(request.getMethod(),
allowedMethods.toArray(new String[allowedMethods.size()]));
} else {
throw new HttpRequestMethodNotSupportedException(request.getMethod(), allowedMethods);
}
else if (!consumableMediaTypes.isEmpty()) {
MediaType contentType = null;
if (StringUtils.hasLength(request.getContentType())) {
contentType = MediaType.parseMediaType(request.getContentType());
}
throw new HttpMediaTypeNotSupportedException(contentType, new ArrayList<MediaType>(consumableMediaTypes));
}
else if (!producibleMediaTypes.isEmpty()) {
throw new HttpMediaTypeNotAcceptableException(new ArrayList<MediaType>(producibleMediaTypes));
}
else {
return null;
}
}
@@ -218,13 +240,13 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
/**
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a
* specific request. For example not all {@link RequestMappingInfo} patterns may apply to the current request.
* Therefore an HttpServletRequest is required as input.
* A comparator for {@link RequestMappingInfo}s. Effective comparison can only be done in the context of a specific
* request. For example not all {@link RequestMappingInfo} patterns may apply to the current request. Therefore an
* HttpServletRequest is required as input.
*
* <p>Furthermore, the following assumptions are made about the input RequestMappings:
* <ul><li>Each RequestMappingInfo has been fully matched to the request <li>The RequestMappingInfo contains
* matched patterns only <li>Patterns are ordered with the best matching pattern at the top </ul>
* <p>Furthermore, the following assumptions are made about the input RequestMappings: <ul><li>Each RequestMappingInfo
* has been fully matched to the request <li>The RequestMappingInfo contains matched patterns only <li>Patterns are
* ordered with the best matching pattern at the top </ul>
*
* @see RequestMappingHandlerMapping#getMatchingMapping(RequestMappingInfo, String, HttpServletRequest)
*/
@@ -289,26 +311,6 @@ public class RequestMappingHandlerMapping extends AbstractHandlerMethodMapping<R
}
}
private int compareAcceptHeaders(List<MediaType> accept, List<MediaType> otherAccept) {
for (MediaType requestAccept : this.requestAcceptHeader) {
int pos1 = indexOfIncluded(requestAccept, accept);
int pos2 = indexOfIncluded(requestAccept, otherAccept);
if (pos1 != pos2) {
return pos2 - pos1;
}
}
return 0;
}
private int indexOfIncluded(MediaType requestAccept, List<MediaType> accept) {
for (int i = 0; i < accept.size(); i++) {
if (requestAccept.includes(accept.get(i))) {
return i;
}
}
return -1;
}
}
}

View File

@@ -17,30 +17,38 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
/**
* A base class for resolving method argument values by reading from the body of a request with
* {@link HttpMessageConverter}s and for handling method return values by writing to the response with
* {@link HttpMessageConverter}s.
*
* A base class for resolving method argument values by reading from the body of a request with {@link
* HttpMessageConverter}s and for handling method return values by writing to the response with {@link
* HttpMessageConverter}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
* @since 3.1
@@ -48,103 +56,161 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
public abstract class AbstractMessageConverterMethodProcessor
implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
private static final MediaType MEDIA_TYPE_APPLICATION = new MediaType("application");
protected final Log logger = LogFactory.getLog(getClass());
private final List<HttpMessageConverter<?>> messageConverters;
private final List<MediaType> allSupportedMediaTypes;
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) {
Assert.notNull(messageConverters, "'messageConverters' must not be null");
Assert.notEmpty(messageConverters, "'messageConverters' must not be empty");
this.messageConverters = messageConverters;
this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters);
}
private static List<MediaType> getAllSupportedMediaTypes(List<HttpMessageConverter<?>> messageConverters) {
Set<MediaType> allSupportedMediaTypes = new HashSet<MediaType>();
for (HttpMessageConverter<?> messageConverter : messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
}
List<MediaType> result = new ArrayList<MediaType>(allSupportedMediaTypes);
MediaType.sortBySpecificity(result);
return Collections.unmodifiableList(result);
}
@SuppressWarnings("unchecked")
protected <T> Object readWithMessageConverters(NativeWebRequest webRequest,
MethodParameter methodParam,
Class<T> paramType)
Class<T> paramType)
throws IOException, HttpMediaTypeNotSupportedException {
HttpInputMessage inputMessage = createInputMessage(webRequest);
MediaType contentType = inputMessage.getHeaders().getContentType();
if (contentType == null) {
StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType()));
String paramName = methodParam.getParameterName();
if (paramName != null) {
builder.append(' ');
builder.append(paramName);
}
throw new HttpMediaTypeNotSupportedException("Cannot read parameter (" + builder.toString() +
") using HttpMessageConverters: no Content-Type found in HTTP request");
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
if (this.messageConverters != null) {
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
if (messageConverter.canRead(paramType, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + "\" using [" +
messageConverter + "]");
}
return ((HttpMessageConverter<T>) messageConverter).read(paramType, inputMessage);
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter.canRead(paramType, contentType)) {
if (logger.isDebugEnabled()) {
logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType + "\" using [" +
messageConverter + "]");
}
return ((HttpMessageConverter<T>) messageConverter).read(paramType, inputMessage);
}
}
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
}
protected abstract HttpInputMessage createInputMessage(NativeWebRequest webRequest);
protected void writeWithMessageConverters(NativeWebRequest webRequest, Object returnValue)
throws IOException, HttpMediaTypeNotAcceptableException {
writeWithMessageConverters(returnValue, createInputMessage(webRequest), createOutputMessage(webRequest));
/**
* Creates a new {@link HttpInputMessage} from the given {@link NativeWebRequest}.
*
* @param webRequest the web request to create an input message from
* @return the input message
*/
protected HttpInputMessage createInputMessage(NativeWebRequest webRequest) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return new ServletServerHttpRequest(servletRequest);
}
protected abstract HttpOutputMessage createOutputMessage(NativeWebRequest webRequest);
/**
* Creates a new {@link HttpOutputMessage} from the given {@link NativeWebRequest}.
*
* @param webRequest the web request to create an output message from
* @return the output message
*/
protected HttpOutputMessage createOutputMessage(NativeWebRequest webRequest) {
HttpServletResponse servletResponse = webRequest.getNativeResponse(HttpServletResponse.class);
return new ServletServerHttpResponse(servletResponse);
}
@SuppressWarnings("unchecked")
protected <T> void writeWithMessageConverters(T returnValue,
HttpInputMessage inputMessage,
protected <T> void writeWithMessageConverters(T returnValue,
MethodParameter returnType,
HttpInputMessage inputMessage,
HttpOutputMessage outputMessage)
throws IOException, HttpMediaTypeNotAcceptableException {
List<MediaType> acceptedMediaTypes = getAcceptedMediaTypes(inputMessage);
List<MediaType> allSupportedMediaTypes = new ArrayList<MediaType>();
if (this.messageConverters != null) {
for (MediaType acceptedMediaType : acceptedMediaTypes) {
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (!messageConverter.canWrite(returnValue.getClass(), acceptedMediaType)) {
continue;
}
((HttpMessageConverter<T>) messageConverter).write(returnValue, acceptedMediaType, outputMessage);
Set<MediaType> producibleMediaTypes = getProducibleMediaTypes(returnType.getMethod(), returnValue.getClass());
Set<MediaType> acceptableMediaTypes = getAcceptableMediaTypes(inputMessage);
List<MediaType> mediaTypes = new ArrayList<MediaType>();
for (MediaType acceptableMediaType : acceptableMediaTypes) {
for (MediaType producibleMediaType : producibleMediaTypes) {
if (acceptableMediaType.isCompatibleWith(producibleMediaType)) {
mediaTypes.add(getMostSpecificMediaType(acceptableMediaType, producibleMediaType));
}
}
}
if (mediaTypes.isEmpty()) {
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
}
MediaType.sortBySpecificity(mediaTypes);
MediaType selectedMediaType = null;
for (MediaType mediaType : mediaTypes) {
if (mediaType.isConcrete()) {
selectedMediaType = mediaType;
break;
}
else if (mediaType.equals(MediaType.ALL) || mediaType.equals(MEDIA_TYPE_APPLICATION)) {
selectedMediaType = MediaType.APPLICATION_OCTET_STREAM;
}
}
if (selectedMediaType != null) {
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter.canWrite(returnValue.getClass(), selectedMediaType)) {
((HttpMessageConverter<T>) messageConverter).write(returnValue, selectedMediaType, outputMessage);
if (logger.isDebugEnabled()) {
MediaType contentType = outputMessage.getHeaders().getContentType();
if (contentType == null) {
contentType = acceptedMediaType;
}
logger.debug("Written [" + returnValue + "] as \"" + contentType + "\" using [" +
logger.debug("Written [" + returnValue + "] as \"" + selectedMediaType + "\" using [" +
messageConverter + "]");
}
return;
}
}
for (HttpMessageConverter<?> messageConverter : messageConverters) {
allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes());
}
}
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
else {
throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes);
}
}
private List<MediaType> getAcceptedMediaTypes(HttpInputMessage inputMessage) {
List<MediaType> acceptedMediaTypes = inputMessage.getHeaders().getAccept();
if (acceptedMediaTypes.isEmpty()) {
acceptedMediaTypes = Collections.singletonList(MediaType.ALL);
private Set<MediaType> getProducibleMediaTypes(Method handlerMethod, Class<?> returnValueClass) {
RequestMapping requestMappingAnn = handlerMethod.getAnnotation(RequestMapping.class);
if (requestMappingAnn == null) {
requestMappingAnn = handlerMethod.getClass().getAnnotation(RequestMapping.class);
}
Set<MediaType> result = new HashSet<MediaType>();
if (requestMappingAnn != null) {
for (String produce : requestMappingAnn.produces()) {
result.add(MediaType.parseMediaType(produce));
}
}
else {
for (HttpMessageConverter<?> messageConverter : messageConverters) {
if (messageConverter.canWrite(returnValueClass, null)) {
result.addAll(messageConverter.getSupportedMediaTypes());
}
}
}
if (result.isEmpty()) {
result.add(MediaType.ALL);
}
return result;
}
MediaType.sortByQualityValue(acceptedMediaTypes);
return acceptedMediaTypes;
private Set<MediaType> getAcceptableMediaTypes(HttpInputMessage inputMessage) {
Set<MediaType> result = new HashSet<MediaType>(inputMessage.getHeaders().getAccept());
if (result.isEmpty()) {
result.add(MediaType.ALL);
}
return result;
}
private MediaType getMostSpecificMediaType(MediaType type1, MediaType type2) {
return MediaType.SPECIFICITY_COMPARATOR.compare(type1, type2) < 0 ? type1 : type2;
}
}

View File

@@ -23,9 +23,6 @@ import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
@@ -34,8 +31,6 @@ import org.springframework.http.HttpOutputMessage;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.util.Assert;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.support.WebDataBinderFactory;
@@ -71,8 +66,10 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws IOException, HttpMediaTypeNotSupportedException {
HttpInputMessage inputMessage = createInputMessage(webRequest);
Class<?> paramType = getHttpEntityType(parameter);
Object body = readWithMessageConverters(webRequest, parameter, paramType);
return new HttpEntity<Object>(body, inputMessage.getHeaders());
}
@@ -88,7 +85,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
else if (typeArgument instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType();
if (componentType instanceof Class) {
// Surely, there should be a nicer way to do this
// Surely, there should be a nicer way to determine the array type
Object array = Array.newInstance((Class<?>) componentType, 0);
return array.getClass();
}
@@ -97,17 +94,12 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
throw new IllegalArgumentException(
"HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized");
}
@Override
protected HttpInputMessage createInputMessage(NativeWebRequest webRequest) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return new ServletServerHttpRequest(servletRequest);
}
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
mavContainer.setResolveView(false);
if (returnValue == null) {
@@ -129,7 +121,7 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
Object body = responseEntity.getBody();
if (body != null) {
writeWithMessageConverters(body, createInputMessage(webRequest), outputMessage);
writeWithMessageConverters(body, returnType, createInputMessage(webRequest), outputMessage);
}
else {
// flush headers to the HttpServletResponse
@@ -137,10 +129,4 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
}
}
@Override
protected HttpOutputMessage createOutputMessage(NativeWebRequest webRequest) {
HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse();
return new ServletServerHttpResponse(servletResponse);
}
}

View File

@@ -18,15 +18,11 @@ package org.springframework.web.servlet.mvc.method.annotation.support;
import java.io.IOException;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpRequest;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
@@ -37,8 +33,8 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
* Resolves method arguments annotated with @{@link RequestBody}.
* Handles return values from methods annotated with @{@link ResponseBody}.
* Resolves method arguments annotated with @{@link RequestBody}. Handles return values from methods annotated with
* {@link ResponseBody}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
@@ -60,25 +56,20 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory)
throws IOException, HttpMediaTypeNotSupportedException {
return readWithMessageConverters(webRequest, parameter, parameter.getParameterType());
}
@Override
protected HttpInputMessage createInputMessage(NativeWebRequest webRequest) {
HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class);
return new ServletServerHttpRequest(servletRequest);
}
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws IOException, HttpMediaTypeNotAcceptableException {
mavContainer.setResolveView(false);
if (returnValue != null) {
writeWithMessageConverters(webRequest, returnValue);
writeWithMessageConverters(returnValue, returnType, createInputMessage(webRequest),
createOutputMessage(webRequest));
}
}
@@ -87,5 +78,5 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter
HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse();
return new ServletServerHttpResponse(servletResponse);
}
}

View File

@@ -19,7 +19,9 @@ package org.springframework.web.servlet.mvc.method.condition;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.springframework.http.MediaType;
@@ -54,6 +56,18 @@ class MediaTypesRequestCondition<T extends MediaTypesRequestCondition.MediaTypeR
return sortedConditions;
}
/**
* Returns all {@link MediaType}s contained in this condition.
*/
public Set<MediaType> getMediaTypes() {
Set<MediaType> result = new LinkedHashSet<MediaType>();
for (MediaTypeRequestCondition condition : getConditions()) {
result.add(condition.getMediaType());
}
return result;
}
/**
* @author Arjen Poutsma
*/