提交 d8e640d7 编写于 作者: J Juergen Hoeller

polishing

上级 0f75cebd
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2011 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -57,10 +57,11 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi ...@@ -57,10 +57,11 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
private MessageType targetType = MessageType.BYTES; private MessageType targetType = MessageType.BYTES;
/** /**
* Construct a new <code>MarshallingMessageConverter</code> with no {@link Marshaller} or {@link Unmarshaller} set. * Construct a new <code>MarshallingMessageConverter</code> with no {@link Marshaller}
* The marshaller must be set after construction by invoking {@link #setMarshaller(Marshaller)} and * or {@link Unmarshaller} set. The marshaller must be set after construction by invoking
* {@link #setUnmarshaller(Unmarshaller)} . * {@link #setMarshaller(Marshaller)} and {@link #setUnmarshaller(Unmarshaller)} .
*/ */
public MarshallingMessageConverter() { public MarshallingMessageConverter() {
} }
...@@ -80,7 +81,7 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi ...@@ -80,7 +81,7 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
if (!(marshaller instanceof Unmarshaller)) { if (!(marshaller instanceof Unmarshaller)) {
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Marshaller [" + marshaller + "] does not implement the Unmarshaller " + "Marshaller [" + marshaller + "] does not implement the Unmarshaller " +
"interface. Please set an Unmarshaller explicitely by using the " + "interface. Please set an Unmarshaller explicitly by using the " +
"MarshallingMessageConverter(Marshaller, Unmarshaller) constructor."); "MarshallingMessageConverter(Marshaller, Unmarshaller) constructor.");
} }
else { else {
...@@ -127,6 +128,7 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi ...@@ -127,6 +128,7 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
* @see MessageType#TEXT * @see MessageType#TEXT
*/ */
public void setTargetType(MessageType targetType) { public void setTargetType(MessageType targetType) {
Assert.notNull(targetType, "MessageType must not be null");
this.targetType = targetType; this.targetType = targetType;
} }
...@@ -251,8 +253,8 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi ...@@ -251,8 +253,8 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
protected Message marshalToMessage(Object object, Session session, Marshaller marshaller, MessageType targetType) protected Message marshalToMessage(Object object, Session session, Marshaller marshaller, MessageType targetType)
throws JMSException, IOException, XmlMappingException { throws JMSException, IOException, XmlMappingException {
throw new IllegalArgumentException( throw new IllegalArgumentException("Unsupported message type [" + targetType +
"Unsupported message type [" + targetType + "]. Cannot marshal to the specified message type."); "]. MarshallingMessageConverter by default only supports TextMessages and BytesMessages.");
} }
...@@ -308,8 +310,8 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi ...@@ -308,8 +310,8 @@ public class MarshallingMessageConverter implements MessageConverter, Initializi
protected Object unmarshalFromMessage(Message message, Unmarshaller unmarshaller) protected Object unmarshalFromMessage(Message message, Unmarshaller unmarshaller)
throws JMSException, IOException, XmlMappingException { throws JMSException, IOException, XmlMappingException {
throw new IllegalArgumentException( throw new IllegalArgumentException("Unsupported message type [" + message.getClass() +
"MarshallingMessageConverter only supports TextMessages and BytesMessages"); "]. MarshallingMessageConverter by default only supports TextMessages and BytesMessages.");
} }
} }
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2011 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -110,11 +110,12 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -110,11 +110,12 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
private ClassLoader classLoader; private ClassLoader classLoader;
/** /**
* Returns the XStream instance used by this marshaller. * Returns the XStream instance used by this marshaller.
*/ */
public XStream getXStream() { public XStream getXStream() {
return xstream; return this.xstream;
} }
/** /**
...@@ -150,7 +151,6 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -150,7 +151,6 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
/** /**
* Sets an alias/type map, consisting of string aliases mapped to classes. Keys are aliases; values are either * Sets an alias/type map, consisting of string aliases mapped to classes. Keys are aliases; values are either
* {@code Class} instances, or String class names. * {@code Class} instances, or String class names.
*
* @see XStream#alias(String, Class) * @see XStream#alias(String, Class)
*/ */
public void setAliases(Map<String, ?> aliases) throws ClassNotFoundException { public void setAliases(Map<String, ?> aliases) throws ClassNotFoundException {
...@@ -165,7 +165,6 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -165,7 +165,6 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
* Sets the aliases by type map, consisting of string aliases mapped to classes. Any class that is assignable to * Sets the aliases by type map, consisting of string aliases mapped to classes. Any class that is assignable to
* this type will be aliased to the same name. Keys are aliases; values are either * this type will be aliased to the same name. Keys are aliases; values are either
* {@code Class} instances, or String class names. * {@code Class} instances, or String class names.
*
* @see XStream#aliasType(String, Class) * @see XStream#aliasType(String, Class)
*/ */
public void setAliasesByType(Map<String, ?> aliases) throws ClassNotFoundException { public void setAliasesByType(Map<String, ?> aliases) throws ClassNotFoundException {
...@@ -325,9 +324,9 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -325,9 +324,9 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
} }
/** /**
* Set the auto-detection mode of XStream. * Set the autodetection mode of XStream.
* <p><strong>Note</strong> that auto-detection implies that the XStream is configured while it is processing the * <p><strong>Note</strong> that auto-detection implies that the XStream is configured while
* XML steams, and thus introduces a potential concurrency problem. * it is processing the XML streams, and thus introduces a potential concurrency problem.
* @see XStream#autodetectAnnotations(boolean) * @see XStream#autodetectAnnotations(boolean)
*/ */
public void setAutodetectAnnotations(boolean autodetectAnnotations) { public void setAutodetectAnnotations(boolean autodetectAnnotations) {
...@@ -358,22 +357,24 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -358,22 +357,24 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
this.supportedClasses = supportedClasses; this.supportedClasses = supportedClasses;
} }
public final void afterPropertiesSet() throws Exception {
customizeXStream(getXStream());
}
public void setBeanClassLoader(ClassLoader classLoader) { public void setBeanClassLoader(ClassLoader classLoader) {
this.classLoader = classLoader; this.classLoader = classLoader;
} }
public final void afterPropertiesSet() throws Exception {
customizeXStream(getXStream());
}
/** /**
* Template to allow for customizing of the given {@link XStream}. * Template to allow for customizing of the given {@link XStream}.
* <p>Default implementation is empty. * <p>The default implementation is empty.
* @param xstream the {@code XStream} instance * @param xstream the {@code XStream} instance
*/ */
protected void customizeXStream(XStream xstream) { protected void customizeXStream(XStream xstream) {
} }
public boolean supports(Class clazz) { public boolean supports(Class clazz) {
if (ObjectUtils.isEmpty(this.supportedClasses)) { if (ObjectUtils.isEmpty(this.supportedClasses)) {
return true; return true;
...@@ -438,8 +439,8 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -438,8 +439,8 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
@Override @Override
protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException { protected void marshalWriter(Object graph, Writer writer) throws XmlMappingException, IOException {
if (streamDriver != null) { if (this.streamDriver != null) {
marshal(graph, streamDriver.createWriter(writer)); marshal(graph, this.streamDriver.createWriter(writer));
} }
else { else {
marshal(graph, new CompactWriter(writer)); marshal(graph, new CompactWriter(writer));
...@@ -467,6 +468,7 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin ...@@ -467,6 +468,7 @@ public class XStreamMarshaller extends AbstractMarshaller implements Initializin
} }
} }
// Unmarshalling // Unmarshalling
@Override @Override
......
/* /*
* Copyright 2002-2010 the original author or authors. * Copyright 2002-2011 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
...@@ -20,7 +20,6 @@ import java.util.Collections; ...@@ -20,7 +20,6 @@ import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
...@@ -28,6 +27,7 @@ import org.codehaus.jackson.JsonEncoding; ...@@ -28,6 +27,7 @@ import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializerFactory; import org.codehaus.jackson.map.SerializerFactory;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils; import org.springframework.util.CollectionUtils;
import org.springframework.validation.BindingResult; import org.springframework.validation.BindingResult;
...@@ -35,19 +35,18 @@ import org.springframework.web.servlet.View; ...@@ -35,19 +35,18 @@ import org.springframework.web.servlet.View;
import org.springframework.web.servlet.view.AbstractView; import org.springframework.web.servlet.view.AbstractView;
/** /**
* Spring-MVC {@link View} that renders JSON content by serializing the model for the current request using <a * Spring MVC {@link View} that renders JSON content by serializing the model for the current request
* href="http://jackson.codehaus.org/">Jackson's</a> {@link ObjectMapper}. * using <a href="http://jackson.codehaus.org/">Jackson's</a> {@link ObjectMapper}.
* *
* <p>By default, the entire contents of the model map (with the exception of framework-specific classes) will be * <p>By default, the entire contents of the model map (with the exception of framework-specific classes)
* encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON alone via * will be encoded as JSON. If the model contains only one key, you can have it extracted encoded as JSON
* {@link #setExtractValueFromSingleKeyModel(boolean)}. Or you can select specific model attributes to be encoded * alone via {@link #setExtractValueFromSingleKeyModel}.
* as JSON via ... TODO
* *
* @author Jeremy Grelle * @author Jeremy Grelle
* @author Arjen Poutsma * @author Arjen Poutsma
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @see org.springframework.http.converter.json.MappingJacksonHttpMessageConverter
* @since 3.0 * @since 3.0
* @see org.springframework.http.converter.json.MappingJacksonHttpMessageConverter
*/ */
public class MappingJacksonJsonView extends AbstractView { public class MappingJacksonJsonView extends AbstractView {
...@@ -56,6 +55,7 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -56,6 +55,7 @@ public class MappingJacksonJsonView extends AbstractView {
*/ */
public static final String DEFAULT_CONTENT_TYPE = "application/json"; public static final String DEFAULT_CONTENT_TYPE = "application/json";
private ObjectMapper objectMapper = new ObjectMapper(); private ObjectMapper objectMapper = new ObjectMapper();
private JsonEncoding encoding = JsonEncoding.UTF8; private JsonEncoding encoding = JsonEncoding.UTF8;
...@@ -68,6 +68,7 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -68,6 +68,7 @@ public class MappingJacksonJsonView extends AbstractView {
private boolean disableCaching = true; private boolean disableCaching = true;
/** /**
* Construct a new {@code JacksonJsonView}, setting the content type to {@code application/json}. * Construct a new {@code JacksonJsonView}, setting the content type to {@code application/json}.
*/ */
...@@ -76,14 +77,15 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -76,14 +77,15 @@ public class MappingJacksonJsonView extends AbstractView {
setExposePathVariables(false); setExposePathVariables(false);
} }
/** /**
* Sets the {@code ObjectMapper} for this view. If not set, a default {@link ObjectMapper#ObjectMapper() ObjectMapper} * Sets the {@code ObjectMapper} for this view.
* is used. * If not set, a default {@link ObjectMapper#ObjectMapper() ObjectMapper} is used.
* * <p>Setting a custom-configured {@code ObjectMapper} is one way to take further control
* <p>Setting a custom-configured {@code ObjectMapper} is one way to take further control of the JSON serialization * of the JSON serialization process. For example, an extended {@link SerializerFactory}
* process. For example, an extended {@link SerializerFactory} can be configured that provides custom serializers for * can be configured that provides custom serializers for specific types. The other option
* specific types. The other option for refining the serialization process is to use Jackson's provided annotations on * for refining the serialization process is to use Jackson's provided annotations on the
* the types to be serialized, in which case a custom-configured ObjectMapper is unnecessary. * types to be serialized, in which case a custom-configured ObjectMapper is unnecessary.
*/ */
public void setObjectMapper(ObjectMapper objectMapper) { public void setObjectMapper(ObjectMapper objectMapper) {
Assert.notNull(objectMapper, "'objectMapper' must not be null"); Assert.notNull(objectMapper, "'objectMapper' must not be null");
...@@ -91,7 +93,8 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -91,7 +93,8 @@ public class MappingJacksonJsonView extends AbstractView {
} }
/** /**
* Sets the {@code JsonEncoding} for this converter. By default, {@linkplain JsonEncoding#UTF8 UTF-8} is used. * Set the {@code JsonEncoding} for this converter.
* By default, {@linkplain JsonEncoding#UTF8 UTF-8} is used.
*/ */
public void setEncoding(JsonEncoding encoding) { public void setEncoding(JsonEncoding encoding) {
Assert.notNull(encoding, "'encoding' must not be null"); Assert.notNull(encoding, "'encoding' must not be null");
...@@ -99,18 +102,19 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -99,18 +102,19 @@ public class MappingJacksonJsonView extends AbstractView {
} }
/** /**
* Indicates whether the JSON output by this view should be prefixed with <tt>"{} && "</tt>. Default is false. * Indicates whether the JSON output by this view should be prefixed with <tt>"{} && "</tt>.
* * Default is false.
* <p> Prefixing the JSON string in this manner is used to help prevent JSON Hijacking. The prefix renders the string * <p>Prefixing the JSON string in this manner is used to help prevent JSON Hijacking.
* syntactically invalid as a script so that it cannot be hijacked. This prefix does not affect the evaluation of JSON, * The prefix renders the string syntactically invalid as a script so that it cannot be hijacked.
* but if JSON validation is performed on the string, the prefix would need to be ignored. * This prefix does not affect the evaluation of JSON, but if JSON validation is performed
* on the string, the prefix would need to be ignored.
*/ */
public void setPrefixJson(boolean prefixJson) { public void setPrefixJson(boolean prefixJson) {
this.prefixJson = prefixJson; this.prefixJson = prefixJson;
} }
/** /**
* Sets the attribute in the model that should be rendered by this view. * Set the attribute in the model that should be rendered by this view.
* When set, all other model attributes will be ignored. * When set, all other model attributes will be ignored.
*/ */
public void setModelKey(String modelKey) { public void setModelKey(String modelKey) {
...@@ -118,7 +122,7 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -118,7 +122,7 @@ public class MappingJacksonJsonView extends AbstractView {
} }
/** /**
* Sets the attributes in the model that should be rendered by this view. * Set the attributes in the model that should be rendered by this view.
* When set, all other model attributes will be ignored. * When set, all other model attributes will be ignored.
*/ */
public void setModelKeys(Set<String> modelKeys) { public void setModelKeys(Set<String> modelKeys) {
...@@ -126,56 +130,56 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -126,56 +130,56 @@ public class MappingJacksonJsonView extends AbstractView {
} }
/** /**
* Returns the attributes in the model that should be rendered by this view. * Return the attributes in the model that should be rendered by this view.
*/ */
public Set<String> getModelKeys() { public Set<String> getModelKeys() {
return modelKeys; return this.modelKeys;
} }
/** /**
* Sets the attributes in the model that should be rendered by this view. * Set the attributes in the model that should be rendered by this view.
* When set, all other model attributes will be ignored. * When set, all other model attributes will be ignored.
* @deprecated use {@link #setModelKeys(Set)} instead * @deprecated use {@link #setModelKeys(Set)} instead
*/ */
@Deprecated
public void setRenderedAttributes(Set<String> renderedAttributes) { public void setRenderedAttributes(Set<String> renderedAttributes) {
this.modelKeys = renderedAttributes; this.modelKeys = renderedAttributes;
} }
/** /**
* Returns the attributes in the model that should be rendered by this view. * Return the attributes in the model that should be rendered by this view.
* @deprecated use {@link #getModelKeys()} instead * @deprecated use {@link #getModelKeys()} instead
*/ */
@Deprecated
public Set<String> getRenderedAttributes() { public Set<String> getRenderedAttributes() {
return modelKeys; return this.modelKeys;
}
/**
* Set whether to serialize models containing a single attribute as a map or whether to
* extract the single value from the model and serialize it directly.
* <p>The effect of setting this flag is similar to using {@code MappingJacksonHttpMessageConverter}
* with an {@code @ResponseBody} request-handling method.
* <p>Default is {@code false}.
*/
public void setExtractValueFromSingleKeyModel(boolean extractValueFromSingleKeyModel) {
this.extractValueFromSingleKeyModel = extractValueFromSingleKeyModel;
} }
/** /**
* Disables caching of the generated JSON. * Disables caching of the generated JSON.
*
* <p>Default is {@code true}, which will prevent the client from caching the generated JSON. * <p>Default is {@code true}, which will prevent the client from caching the generated JSON.
*/ */
public void setDisableCaching(boolean disableCaching) { public void setDisableCaching(boolean disableCaching) {
this.disableCaching = disableCaching; this.disableCaching = disableCaching;
} }
/**
* Set whether to serialize models containing a single attribute as a map or whether to
* extract the single value from the model and serialize it directly.
* The effect of setting this flag is similar to using
* {@code MappingJacksonHttpMessageConverter} with an {@code @ResponseBody}.
* request-handling method.
*
* <p>Default is {@code false}.
*/
public void setExtractValueFromSingleKeyModel(boolean extractValueFromSingleKeyModel) {
this.extractValueFromSingleKeyModel = extractValueFromSingleKeyModel;
}
@Override @Override
protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) { protected void prepareResponse(HttpServletRequest request, HttpServletResponse response) {
response.setContentType(getContentType()); response.setContentType(getContentType());
response.setCharacterEncoding(encoding.getJavaName()); response.setCharacterEncoding(this.encoding.getJavaName());
if (disableCaching) { if (this.disableCaching) {
response.addHeader("Pragma", "no-cache"); response.addHeader("Pragma", "no-cache");
response.addHeader("Cache-Control", "no-cache, no-store, max-age=0"); response.addHeader("Cache-Control", "no-cache, no-store, max-age=0");
response.addDateHeader("Expires", 1L); response.addDateHeader("Expires", 1L);
...@@ -183,38 +187,35 @@ public class MappingJacksonJsonView extends AbstractView { ...@@ -183,38 +187,35 @@ public class MappingJacksonJsonView extends AbstractView {
} }
@Override @Override
protected void renderMergedOutputModel(Map<String, Object> model, protected void renderMergedOutputModel(Map<String, Object> model, HttpServletRequest request,
HttpServletRequest request,
HttpServletResponse response) throws Exception { HttpServletResponse response) throws Exception {
Object value = filterModel(model); Object value = filterModel(model);
JsonGenerator generator = JsonGenerator generator =
objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), encoding); this.objectMapper.getJsonFactory().createJsonGenerator(response.getOutputStream(), this.encoding);
if (prefixJson) { if (this.prefixJson) {
generator.writeRaw("{} && "); generator.writeRaw("{} && ");
} }
objectMapper.writeValue(generator, value); this.objectMapper.writeValue(generator, value);
} }
/** /**
* Filters out undesired attributes from the given model. The return value can be either another {@link Map}, or a * Filters out undesired attributes from the given model.
* single value object. * The return value can be either another {@link Map} or a single value object.
* * <p>The default implementation removes {@link BindingResult} instances and entries
* <p>Default implementation removes {@link BindingResult} instances and entries not included in the {@link * not included in the {@link #setRenderedAttributes renderedAttributes} property.
* #setRenderedAttributes(Set) renderedAttributes} property.
*
* @param model the model, as passed on to {@link #renderMergedOutputModel} * @param model the model, as passed on to {@link #renderMergedOutputModel}
* @return the object to be rendered * @return the object to be rendered
*/ */
protected Object filterModel(Map<String, Object> model) { protected Object filterModel(Map<String, Object> model) {
Map<String, Object> result = new HashMap<String, Object>(model.size()); Map<String, Object> result = new HashMap<String, Object>(model.size());
Set<String> renderedAttributes = Set<String> renderedAttributes = (!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet());
!CollectionUtils.isEmpty(this.modelKeys) ? this.modelKeys : model.keySet();
for (Map.Entry<String, Object> entry : model.entrySet()) { for (Map.Entry<String, Object> entry : model.entrySet()) {
if (!(entry.getValue() instanceof BindingResult) && renderedAttributes.contains(entry.getKey())) { if (!(entry.getValue() instanceof BindingResult) && renderedAttributes.contains(entry.getKey())) {
result.put(entry.getKey(), entry.getValue()); result.put(entry.getKey(), entry.getValue());
} }
} }
return (this.extractValueFromSingleKeyModel && result.size() == 1) ? result.values().iterator().next() : result; return (this.extractValueFromSingleKeyModel && result.size() == 1 ? result.values().iterator().next() : result);
} }
} }
...@@ -474,7 +474,6 @@ public class MediaType implements Comparable<MediaType> { ...@@ -474,7 +474,6 @@ public class MediaType implements Comparable<MediaType> {
int otherPlusIdx = other.subtype.indexOf('+'); int otherPlusIdx = other.subtype.indexOf('+');
if (thisPlusIdx != -1 && otherPlusIdx != -1) { if (thisPlusIdx != -1 && otherPlusIdx != -1) {
String thisSubtypeNoSuffix = this.subtype.substring(0, thisPlusIdx); String thisSubtypeNoSuffix = this.subtype.substring(0, thisPlusIdx);
String thisSubtypeSuffix = this.subtype.substring(thisPlusIdx + 1); String thisSubtypeSuffix = this.subtype.substring(thisPlusIdx + 1);
String otherSubtypeSuffix = other.subtype.substring(otherPlusIdx + 1); String otherSubtypeSuffix = other.subtype.substring(otherPlusIdx + 1);
if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) { if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) {
......
...@@ -16,16 +16,13 @@ ...@@ -16,16 +16,13 @@
package org.springframework.http.converter.json; package org.springframework.http.converter.json;
import java.io.EOFException;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.Charset; import java.nio.charset.Charset;
import java.util.List; import java.util.List;
import org.codehaus.jackson.JsonEncoding; import org.codehaus.jackson.JsonEncoding;
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.JsonGenerator; import org.codehaus.jackson.JsonGenerator;
import org.codehaus.jackson.JsonParseException; import org.codehaus.jackson.JsonProcessingException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.type.TypeFactory; import org.codehaus.jackson.map.type.TypeFactory;
import org.codehaus.jackson.type.JavaType; import org.codehaus.jackson.type.JavaType;
...@@ -55,6 +52,7 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve ...@@ -55,6 +52,7 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8"); public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
private ObjectMapper objectMapper = new ObjectMapper(); private ObjectMapper objectMapper = new ObjectMapper();
private boolean prefixJson = false; private boolean prefixJson = false;
...@@ -106,27 +104,6 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve ...@@ -106,27 +104,6 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType)); return (this.objectMapper.canDeserialize(javaType) && canRead(mediaType));
} }
/**
* Returns the Jackson {@link JavaType} for the specific class.
* <p>The 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&lt;?&gt; 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));
...@@ -146,36 +123,57 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve ...@@ -146,36 +123,57 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
try { try {
return this.objectMapper.readValue(inputMessage.getBody(), javaType); return this.objectMapper.readValue(inputMessage.getBody(), javaType);
} }
catch (JsonParseException ex) { catch (JsonProcessingException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
catch (JsonMappingException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
}
catch (EOFException ex) {
throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex); throw new HttpMessageNotReadableException("Could not read JSON: " + ex.getMessage(), ex);
} }
} }
@Override @Override
protected void writeInternal(Object o, HttpOutputMessage outputMessage) protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException { throws IOException, HttpMessageNotWritableException {
JsonEncoding encoding = getEncoding(outputMessage.getHeaders().getContentType()); JsonEncoding encoding = getJsonEncoding(outputMessage.getHeaders().getContentType());
JsonGenerator jsonGenerator = JsonGenerator jsonGenerator =
this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding); this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
try { try {
if (this.prefixJson) { if (this.prefixJson) {
jsonGenerator.writeRaw("{} && "); jsonGenerator.writeRaw("{} && ");
} }
this.objectMapper.writeValue(jsonGenerator, o); this.objectMapper.writeValue(jsonGenerator, object);
} }
catch (JsonGenerationException ex) { catch (JsonProcessingException ex) {
throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex); throw new HttpMessageNotWritableException("Could not write JSON: " + ex.getMessage(), ex);
} }
} }
private JsonEncoding getEncoding(MediaType contentType) {
/**
* Return the Jackson {@link JavaType} for the specified class.
* <p>The 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&lt;?&gt; 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);
}
/**
* Determine the JSON encoding to use for the given content type.
* @param contentType the media type as requested by the caller
* @return the JSON encoding to use (never <code>null</code>)
*/
protected JsonEncoding getJsonEncoding(MediaType contentType) {
if (contentType != null && contentType.getCharSet() != null) { if (contentType != null && contentType.getCharSet() != null) {
Charset charset = contentType.getCharSet(); Charset charset = contentType.getCharSet();
for (JsonEncoding encoding : JsonEncoding.values()) { for (JsonEncoding encoding : JsonEncoding.values()) {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册