SPR-7002 - RestTemplate fails to convert properly for Generic Type Container with MappingJacksonHttpMessageConverter
This commit is contained in:
parent
f7ac7a395c
commit
212daa1995
|
|
@ -86,13 +86,34 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
|
||||||
this.prefixJson = prefixJson;
|
this.prefixJson = prefixJson;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canRead(Class<?> clazz, MediaType mediaType) {
|
public boolean canRead(Class<?> clazz, MediaType mediaType) {
|
||||||
JavaType javaType = TypeFactory.fromClass(clazz);
|
JavaType javaType = getJavaType(clazz);
|
||||||
return this.objectMapper.canDeserialize(javaType) && canRead(mediaType);
|
return this.objectMapper.canDeserialize(javaType) && canRead(mediaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Jackson {@link JavaType} for the specific class.
|
||||||
|
*
|
||||||
|
* <p>Default implementation returns {@link TypeFactory#type(java.lang.reflect.Type)}, but this can be overridden
|
||||||
|
* in subclasses, to allow for custom generic collection handling. For instance:
|
||||||
|
* <pre class="code">
|
||||||
|
* protected JavaType getJavaType(Class<?> clazz) {
|
||||||
|
* if (List.class.isAssignableFrom(clazz)) {
|
||||||
|
* return TypeFactory.collectionType(ArrayList.class, MyBean.class);
|
||||||
|
* } else {
|
||||||
|
* return super.getJavaType(clazz);
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
* </pre>
|
||||||
|
*
|
||||||
|
* @param clazz the class to return the java type for
|
||||||
|
* @return the java type
|
||||||
|
*/
|
||||||
|
protected JavaType getJavaType(Class<?> clazz) {
|
||||||
|
return TypeFactory.type(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
|
||||||
return this.objectMapper.canSerialize(clazz) && canWrite(mediaType);
|
return this.objectMapper.canSerialize(clazz) && canWrite(mediaType);
|
||||||
|
|
@ -107,8 +128,8 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
|
||||||
@Override
|
@Override
|
||||||
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
|
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
|
||||||
throws IOException, HttpMessageNotReadableException {
|
throws IOException, HttpMessageNotReadableException {
|
||||||
|
JavaType javaType = getJavaType(clazz);
|
||||||
return this.objectMapper.readValue(inputMessage.getBody(), clazz);
|
return this.objectMapper.readValue(inputMessage.getBody(), javaType);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,8 @@ import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.codehaus.jackson.map.type.TypeFactory;
|
||||||
|
import org.codehaus.jackson.type.JavaType;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
@ -56,7 +58,6 @@ public class MappingJacksonHttpMessageConverterTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
|
||||||
public void readTyped() throws IOException {
|
public void readTyped() throws IOException {
|
||||||
String body =
|
String body =
|
||||||
"{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
"{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}";
|
||||||
|
|
@ -71,6 +72,36 @@ public class MappingJacksonHttpMessageConverterTests {
|
||||||
assertArrayEquals(new byte[]{0x1, 0x2}, result.getBytes());
|
assertArrayEquals(new byte[]{0x1, 0x2}, result.getBytes());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public void readGenerics() throws IOException {
|
||||||
|
converter = new MappingJacksonHttpMessageConverter() {
|
||||||
|
@Override
|
||||||
|
protected JavaType getJavaType(Class<?> clazz) {
|
||||||
|
if (List.class.isAssignableFrom(clazz)) {
|
||||||
|
return TypeFactory.collectionType(ArrayList.class, MyBean.class);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return super.getJavaType(clazz);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
String body =
|
||||||
|
"[{\"bytes\":\"AQI=\",\"array\":[\"Foo\",\"Bar\"],\"number\":42,\"string\":\"Foo\",\"bool\":true,\"fraction\":42.0}]";
|
||||||
|
MockHttpInputMessage inputMessage = new MockHttpInputMessage(body.getBytes("UTF-8"));
|
||||||
|
inputMessage.getHeaders().setContentType(new MediaType("application", "json"));
|
||||||
|
|
||||||
|
List<MyBean> results = (List<MyBean>) converter.read(List.class, inputMessage);
|
||||||
|
assertEquals(1, results.size());
|
||||||
|
MyBean result = results.get(0);
|
||||||
|
assertEquals("Foo", result.getString());
|
||||||
|
assertEquals(42, result.getNumber());
|
||||||
|
assertEquals(42F, result.getFraction(), 0F);
|
||||||
|
assertArrayEquals(new String[]{"Foo", "Bar"}, result.getArray());
|
||||||
|
assertTrue(result.isBool());
|
||||||
|
assertArrayEquals(new byte[]{0x1, 0x2}, result.getBytes());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
public void readUntyped() throws IOException {
|
public void readUntyped() throws IOException {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue