Fix issue with generic @RequestBody arguments

The original commit c9b7b1 ensured the ability to read parameterized
type @RequestBody arguments via GenericHttpMessageConverter (e.g.
application/json and List<String>). However, it also affected the
ability to read @RequestBody arguments that happen are parameterized
but aren't treated as such (e.g. application/x-www-form-urlencoded and
MultiValueMap<String, String>). This commit corrects the issue.

Issue: SPR-9570
This commit is contained in:
Rossen Stoyanchev
2012-10-31 21:08:02 -04:00
parent 0e3aa0eec4
commit c0baea58c0
4 changed files with 101 additions and 36 deletions

View File

@@ -17,6 +17,9 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
@@ -107,15 +110,15 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
* @throws HttpMediaTypeNotSupportedException if no suitable message converter is found
*/
@SuppressWarnings("unchecked")
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter methodParam,
Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage,
MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException {
MediaType contentType = inputMessage.getHeaders().getContentType();
if (contentType == null) {
contentType = MediaType.APPLICATION_OCTET_STREAM;
}
Class<T> paramClass = (paramType instanceof Class) ? (Class) paramType : null;
Class<T> paramClass = getParamClass(paramType);
for (HttpMessageConverter<?> messageConverter : this.messageConverters) {
if (messageConverter instanceof GenericHttpMessageConverter) {
@@ -142,6 +145,26 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements
throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes);
}
private Class getParamClass(Type paramType) {
if (paramType instanceof Class) {
return (Class) paramType;
}
else if (paramType instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) paramType).getGenericComponentType();
if (componentType instanceof Class) {
// Surely, there should be a nicer way to determine the array type
return Array.newInstance((Class<?>) componentType, 0).getClass();
}
}
else if (paramType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) paramType;
if (parameterizedType.getRawType() instanceof Class) {
return (Class) parameterizedType.getRawType();
}
}
return null;
}
/**
* Creates a new {@link HttpInputMessage} from the given {@link NativeWebRequest}.
*

View File

@@ -17,8 +17,6 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
@@ -89,23 +87,11 @@ public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodPro
Assert.isAssignable(HttpEntity.class, parameter.getParameterType());
ParameterizedType type = (ParameterizedType) parameter.getGenericParameterType();
if (type.getActualTypeArguments().length == 1) {
Type typeArgument = type.getActualTypeArguments()[0];
if (typeArgument instanceof Class) {
return (Class<?>) typeArgument;
}
else if (typeArgument instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType();
if (componentType instanceof Class) {
// Surely, there should be a nicer way to determine the array type
return Array.newInstance((Class<?>) componentType, 0).getClass();
}
}
else if (typeArgument instanceof ParameterizedType) {
return typeArgument;
}
return type.getActualTypeArguments()[0];
}
throw new IllegalArgumentException("HttpEntity parameter (" + parameter.getParameterName() + ") "
+ "in method " + parameter.getMethod() + "is not parameterized");
throw new IllegalArgumentException("HttpEntity parameter ("
+ parameter.getParameterName() + ") in method " + parameter.getMethod()
+ " is not parameterized or has more than one parameter");
}
public void handleReturnValue(