diff --git a/org.springframework.web/src/main/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java b/org.springframework.web/src/main/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java
index dfb2681b403..b076cc390d8 100644
--- a/org.springframework.web/src/main/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java
+++ b/org.springframework.web/src/main/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverter.java
@@ -20,9 +20,14 @@ import java.io.IOException;
import java.nio.charset.Charset;
import java.util.List;
+import javax.xml.bind.Marshaller;
+import javax.xml.bind.PropertyException;
+
import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator;
+import org.codehaus.jackson.type.JavaType;
import org.codehaus.jackson.map.ObjectMapper;
+import org.codehaus.jackson.map.type.TypeFactory;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
@@ -39,24 +44,24 @@ import org.springframework.util.Assert;
*
This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances.
*
*
By default, this converter supports {@code application/json}. This can be overridden by setting the {@link
- * #setSupportedMediaTypes(List) supportedMediaTypes} property, and overriding the {@link #getContentType(Object)}
+ * #setSupportedMediaTypes(List) supportedMediaTypes} property.
* method.
*
* @author Arjen Poutsma
* @see org.springframework.web.servlet.view.json.BindingJacksonJsonView
* @since 3.0
*/
-public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter {
+public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter {
+
+ public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private ObjectMapper objectMapper = new ObjectMapper();
- private JsonEncoding encoding = JsonEncoding.UTF8;
-
private boolean prefixJson = false;
/** Construct a new {@code BindingJacksonHttpMessageConverter}, */
public MappingJacksonHttpMessageConverter() {
- super(new MediaType("application", "json"));
+ super(new MediaType("application", "json", DEFAULT_CHARSET));
}
/**
@@ -73,12 +78,6 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageCo
this.objectMapper = objectMapper;
}
- /** Sets the {@code JsonEncoding} for this converter. By default, {@linkplain JsonEncoding#UTF8 UTF-8} is used. */
- public void setEncoding(JsonEncoding encoding) {
- Assert.notNull(encoding, "'encoding' must not be null");
- this.encoding = encoding;
- }
-
/**
* Indicates whether the JSON output by this view should be prefixed with "{} &&". Default is false.
*
@@ -91,30 +90,50 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageCo
}
@Override
- public boolean supports(Class extends T> clazz) {
- return objectMapper.canSerialize(clazz);
+ public boolean canRead(Class> clazz, MediaType mediaType) {
+ JavaType javaType = TypeFactory.fromClass(clazz);
+ return objectMapper.canDeserialize(javaType) && isSupported(mediaType);
}
@Override
- protected T readInternal(Class clazz, HttpInputMessage inputMessage)
+ public boolean canWrite(Class> clazz, MediaType mediaType) {
+ return objectMapper.canSerialize(clazz) && isSupported(mediaType);
+ }
+
+ @Override
+ protected boolean supports(Class> clazz) {
+ // should not be called, since we override canRead/Write
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ protected Object readInternal(Class clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(inputMessage.getBody(), clazz);
}
@Override
- protected MediaType getDefaultContentType(T t) {
- Charset charset = Charset.forName(encoding.getJavaName());
- return new MediaType("application", "json", charset);
- }
-
- @Override
- protected void writeInternal(T t, HttpOutputMessage outputMessage)
+ protected void writeInternal(Object o, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
+ JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType());
JsonGenerator jsonGenerator =
objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
if (prefixJson) {
jsonGenerator.writeRaw("{} && ");
}
- objectMapper.writeValue(jsonGenerator, t);
+ objectMapper.writeValue(jsonGenerator, o);
}
+
+ private JsonEncoding getEncoding(MediaType contentType) {
+ if (contentType != null && contentType.getCharSet() != null) {
+ Charset charset = contentType.getCharSet();
+ for (JsonEncoding encoding : JsonEncoding.values()) {
+ if (charset.name().equals(encoding.getJavaName())) {
+ return encoding;
+ }
+ }
+ }
+ return JsonEncoding.UTF8;
+ }
+
}
diff --git a/org.springframework.web/src/test/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverterTests.java b/org.springframework.web/src/test/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverterTests.java
index 501d90ad981..1fd36ee12ec 100644
--- a/org.springframework.web/src/test/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverterTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/http/converter/json/MappingJacksonHttpMessageConverterTests.java
@@ -21,6 +21,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import static org.junit.Assert.*;
import org.junit.Before;
@@ -33,25 +34,33 @@ import org.springframework.http.MockHttpOutputMessage;
/** @author Arjen Poutsma */
public class MappingJacksonHttpMessageConverterTests {
- private MappingJacksonHttpMessageConverter converter;
+ private MappingJacksonHttpMessageConverter converter;
@Before
public void setUp() {
- converter = new MappingJacksonHttpMessageConverter();
+ converter = new MappingJacksonHttpMessageConverter();
}
@Test
- public void supports() {
- assertTrue(converter.supports(MyBean.class));
+ public void canRead() {
+ assertTrue(converter.canRead(MyBean.class, new MediaType("application", "json")));
+ assertTrue(converter.canRead(Map.class, new MediaType("application", "json")));
}
@Test
+ public void canWrite() {
+ assertTrue(converter.canWrite(MyBean.class, new MediaType("application", "json")));
+ assertTrue(converter.canWrite(Map.class, new MediaType("application", "json")));
+ }
+
+ @Test
+ @SuppressWarnings("unchecked")
public void readTyped() throws IOException {
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"));
- MyBean result = converter.read(MyBean.class, inputMessage);
+ MyBean result = (MyBean) converter.read((Class) MyBean.class, inputMessage);
assertEquals("Foo", result.getString());
assertEquals(42, result.getNumber());
assertEquals(42F, result.getFraction(), 0F);
@@ -61,14 +70,13 @@ public class MappingJacksonHttpMessageConverterTests {
}
@Test
- @SuppressWarnings({"unchecked"})
+ @SuppressWarnings("unchecked")
public void readUntyped() throws IOException {
- MappingJacksonHttpMessageConverter converter = new MappingJacksonHttpMessageConverter();
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"));
- HashMap result = converter.read(HashMap.class, inputMessage);
+ HashMap result = (HashMap) converter.read((Class)HashMap.class, inputMessage);
assertEquals("Foo", result.get("string"));
assertEquals(42, result.get("number"));
assertEquals(42D, (Double) result.get("fraction"), 0D);
@@ -103,6 +111,18 @@ public class MappingJacksonHttpMessageConverterTests {
outputMessage.getHeaders().getContentType());
}
+ @Test
+ public void writeUTF16() throws IOException {
+ Charset utf16 = Charset.forName("UTF-16BE");
+ MediaType contentType = new MediaType("application", "json", utf16);
+ MockHttpOutputMessage outputMessage = new MockHttpOutputMessage();
+ String body = "H\u00e9llo W\u00f6rld";
+ converter.write(body, contentType, outputMessage);
+ assertEquals("Invalid result", "\"" + body + "\"", outputMessage.getBodyAsString(utf16));
+ assertEquals("Invalid content-type", contentType, outputMessage.getHeaders().getContentType());
+ }
+
+
public static class MyBean {
private String string;