Fix ParameterizedType + contextClass support in Jackson converter
Issue: SPR-14470
This commit is contained in:
parent
b52b56c94e
commit
3a4e5d5da8
|
@ -17,6 +17,7 @@
|
|||
package org.springframework.http.converter.json;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.lang.reflect.TypeVariable;
|
||||
import java.nio.charset.Charset;
|
||||
|
@ -312,11 +313,37 @@ public abstract class AbstractJackson2HttpMessageConverter extends AbstractGener
|
|||
*/
|
||||
protected JavaType getJavaType(Type type, Class<?> contextClass) {
|
||||
TypeFactory typeFactory = this.objectMapper.getTypeFactory();
|
||||
if (type instanceof TypeVariable && contextClass != null) {
|
||||
ResolvableType resolvedType = resolveVariable(
|
||||
(TypeVariable<?>) type, ResolvableType.forClass(contextClass));
|
||||
if (resolvedType != ResolvableType.NONE) {
|
||||
return typeFactory.constructType(resolvedType.resolve());
|
||||
if (contextClass != null) {
|
||||
ResolvableType resolvedType = ResolvableType.forType(type);
|
||||
if (type instanceof TypeVariable) {
|
||||
ResolvableType resolvedTypeVariable = resolveVariable(
|
||||
(TypeVariable<?>) type, ResolvableType.forClass(contextClass));
|
||||
if (resolvedTypeVariable != ResolvableType.NONE) {
|
||||
return typeFactory.constructType(resolvedTypeVariable.resolve());
|
||||
}
|
||||
}
|
||||
else if (type instanceof ParameterizedType && resolvedType.hasUnresolvableGenerics()) {
|
||||
ParameterizedType parameterizedType = (ParameterizedType) type;
|
||||
Class<?>[] generics = new Class<?>[parameterizedType.getActualTypeArguments().length];
|
||||
Type[] typeArguments = parameterizedType.getActualTypeArguments();
|
||||
for (int i = 0; i < typeArguments.length; i++) {
|
||||
Type typeArgument = typeArguments[i];
|
||||
if (typeArgument instanceof TypeVariable) {
|
||||
ResolvableType resolvedTypeArgument = resolveVariable(
|
||||
(TypeVariable<?>) typeArgument, ResolvableType.forClass(contextClass));
|
||||
if (resolvedTypeArgument != ResolvableType.NONE) {
|
||||
generics[i] = resolvedTypeArgument.resolve();
|
||||
}
|
||||
else {
|
||||
generics[i] = ResolvableType.forType(typeArgument).resolve();
|
||||
}
|
||||
}
|
||||
else {
|
||||
generics[i] = ResolvableType.forType(typeArgument).resolve();
|
||||
}
|
||||
}
|
||||
return typeFactory.constructType(ResolvableType.
|
||||
forClassWithGenerics(resolvedType.getRawClass(), generics).getType());
|
||||
}
|
||||
}
|
||||
return typeFactory.constructType(type);
|
||||
|
|
|
@ -240,6 +240,29 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
assertEquals("Jad", result.getName());
|
||||
}
|
||||
|
||||
@Test // SPR-14470
|
||||
public void resolveParameterizedWithTypeVariableArgument() throws Exception {
|
||||
Method method = MyParameterizedControllerWithList.class.getMethod("handleDto", List.class);
|
||||
HandlerMethod handlerMethod = new HandlerMethod(new MySimpleParameterizedControllerWithList(), method);
|
||||
MethodParameter methodParam = handlerMethod.getMethodParameters()[0];
|
||||
|
||||
String content = "[{\"name\" : \"Jad\"}, {\"name\" : \"Robert\"}]";
|
||||
this.servletRequest.setContent(content.getBytes("UTF-8"));
|
||||
this.servletRequest.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
|
||||
List<HttpMessageConverter<?>> converters = new ArrayList<>();
|
||||
converters.add(new MappingJackson2HttpMessageConverter());
|
||||
RequestResponseBodyMethodProcessor processor = new RequestResponseBodyMethodProcessor(converters);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<SimpleBean> result = (List<SimpleBean>)
|
||||
processor.resolveArgument(methodParam, container, request, factory);
|
||||
|
||||
assertNotNull(result);
|
||||
assertEquals("Jad", result.get(0).getName());
|
||||
assertEquals("Robert", result.get(1).getName());
|
||||
}
|
||||
|
||||
@Test // SPR-11225
|
||||
public void resolveArgumentTypeVariableWithNonGenericConverter() throws Exception {
|
||||
Method method = MyParameterizedController.class.getMethod("handleDto", Identifiable.class);
|
||||
|
@ -725,6 +748,17 @@ public class RequestResponseBodyMethodProcessorTests {
|
|||
void setId(Long id);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static abstract class MyParameterizedControllerWithList<DTO extends Identifiable> {
|
||||
|
||||
public void handleDto(@RequestBody List<DTO> dto) {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private static class MySimpleParameterizedControllerWithList extends MyParameterizedControllerWithList<SimpleBean> {
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings({ "serial" })
|
||||
private static class SimpleBean implements Identifiable {
|
||||
|
|
Loading…
Reference in New Issue