|
|
|
@ -20,9 +20,14 @@ import java.io.IOException; |
|
|
|
import java.nio.charset.Charset; |
|
|
|
import java.nio.charset.Charset; |
|
|
|
import java.util.List; |
|
|
|
import java.util.List; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
import javax.xml.bind.Marshaller; |
|
|
|
|
|
|
|
import javax.xml.bind.PropertyException; |
|
|
|
|
|
|
|
|
|
|
|
import org.codehaus.jackson.JsonEncoding; |
|
|
|
import org.codehaus.jackson.JsonEncoding; |
|
|
|
import org.codehaus.jackson.JsonGenerator; |
|
|
|
import org.codehaus.jackson.JsonGenerator; |
|
|
|
|
|
|
|
import org.codehaus.jackson.type.JavaType; |
|
|
|
import org.codehaus.jackson.map.ObjectMapper; |
|
|
|
import org.codehaus.jackson.map.ObjectMapper; |
|
|
|
|
|
|
|
import org.codehaus.jackson.map.type.TypeFactory; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.http.HttpInputMessage; |
|
|
|
import org.springframework.http.HttpInputMessage; |
|
|
|
import org.springframework.http.HttpOutputMessage; |
|
|
|
import org.springframework.http.HttpOutputMessage; |
|
|
|
@ -39,24 +44,24 @@ import org.springframework.util.Assert; |
|
|
|
* <p>This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances. |
|
|
|
* <p>This converter can be used to bind to typed beans, or untyped {@link java.util.HashMap HashMap} instances. |
|
|
|
* |
|
|
|
* |
|
|
|
* <p>By default, this converter supports {@code application/json}. This can be overridden by setting the {@link |
|
|
|
* <p>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. |
|
|
|
* method. |
|
|
|
* |
|
|
|
* |
|
|
|
* @author Arjen Poutsma |
|
|
|
* @author Arjen Poutsma |
|
|
|
* @see org.springframework.web.servlet.view.json.BindingJacksonJsonView |
|
|
|
* @see org.springframework.web.servlet.view.json.BindingJacksonJsonView |
|
|
|
* @since 3.0 |
|
|
|
* @since 3.0 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class MappingJacksonHttpMessageConverter<T> extends AbstractHttpMessageConverter<T> { |
|
|
|
public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter<Object> { |
|
|
|
|
|
|
|
|
|
|
|
private ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); |
|
|
|
|
|
|
|
|
|
|
|
private JsonEncoding encoding = JsonEncoding.UTF8; |
|
|
|
private ObjectMapper objectMapper = new ObjectMapper(); |
|
|
|
|
|
|
|
|
|
|
|
private boolean prefixJson = false; |
|
|
|
private boolean prefixJson = false; |
|
|
|
|
|
|
|
|
|
|
|
/** Construct a new {@code BindingJacksonHttpMessageConverter}, */ |
|
|
|
/** Construct a new {@code BindingJacksonHttpMessageConverter}, */ |
|
|
|
public MappingJacksonHttpMessageConverter() { |
|
|
|
public MappingJacksonHttpMessageConverter() { |
|
|
|
super(new MediaType("application", "json")); |
|
|
|
super(new MediaType("application", "json", DEFAULT_CHARSET)); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -73,12 +78,6 @@ public class MappingJacksonHttpMessageConverter<T> extends AbstractHttpMessageCo |
|
|
|
this.objectMapper = objectMapper; |
|
|
|
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. |
|
|
|
* Indicates whether the JSON output by this view should be prefixed with "{} &&". Default is false. |
|
|
|
* |
|
|
|
* |
|
|
|
@ -91,30 +90,50 @@ public class MappingJacksonHttpMessageConverter<T> extends AbstractHttpMessageCo |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public boolean supports(Class<? extends T> clazz) { |
|
|
|
public boolean canRead(Class<?> clazz, MediaType mediaType) { |
|
|
|
return objectMapper.canSerialize(clazz); |
|
|
|
JavaType javaType = TypeFactory.fromClass(clazz); |
|
|
|
|
|
|
|
return objectMapper.canDeserialize(javaType) && isSupported(mediaType); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected T readInternal(Class<T> clazz, HttpInputMessage inputMessage) |
|
|
|
public boolean canWrite(Class<?> clazz, MediaType mediaType) { |
|
|
|
throws IOException, HttpMessageNotReadableException { |
|
|
|
return objectMapper.canSerialize(clazz) && isSupported(mediaType); |
|
|
|
return objectMapper.readValue(inputMessage.getBody(), clazz); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
|
|
|
protected boolean supports(Class<?> clazz) { |
|
|
|
|
|
|
|
// should not be called, since we override canRead/Write
|
|
|
|
|
|
|
|
throw new UnsupportedOperationException(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected MediaType getDefaultContentType(T t) { |
|
|
|
protected Object readInternal(Class<Object> clazz, HttpInputMessage inputMessage) |
|
|
|
Charset charset = Charset.forName(encoding.getJavaName()); |
|
|
|
throws IOException, HttpMessageNotReadableException { |
|
|
|
return new MediaType("application", "json", charset); |
|
|
|
return objectMapper.readValue(inputMessage.getBody(), clazz); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
protected void writeInternal(T t, HttpOutputMessage outputMessage) |
|
|
|
protected void writeInternal(Object o, HttpOutputMessage outputMessage) |
|
|
|
throws IOException, HttpMessageNotWritableException { |
|
|
|
throws IOException, HttpMessageNotWritableException { |
|
|
|
|
|
|
|
JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType()); |
|
|
|
JsonGenerator jsonGenerator = |
|
|
|
JsonGenerator jsonGenerator = |
|
|
|
objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding); |
|
|
|
objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding); |
|
|
|
if (prefixJson) { |
|
|
|
if (prefixJson) { |
|
|
|
jsonGenerator.writeRaw("{} && "); |
|
|
|
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; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|