relaxed generic Class declaration in HttpMessageConverter's canRead/canWrite/read signatures (SPR-6848)

This commit is contained in:
Juergen Hoeller 2010-02-16 17:46:16 +00:00
parent 19cdd558d3
commit 4ae1709313
13 changed files with 197 additions and 188 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -34,11 +34,12 @@ import org.springframework.util.Assert;
/**
* Abstract base class for most {@link HttpMessageConverter} implementations.
*
* <p>This base class adds support for setting supported {@code MediaTypes}, through the {@link
* #setSupportedMediaTypes(List) supportedMediaTypes} bean property. It also adds support for {@code Content-Type} and
* {@code Content-Length} when writing to output messages.
* <p>This base class adds support for setting supported {@code MediaTypes}, through the
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} bean property. It also adds
* support for {@code Content-Type} and {@code Content-Length} when writing to output messages.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
*/
public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConverter<T> {
@ -48,9 +49,9 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
private List<MediaType> supportedMediaTypes = Collections.emptyList();
/**
* Construct an {@code AbstractHttpMessageConverter} with no supported media types.
*
* @see #setSupportedMediaTypes
*/
protected AbstractHttpMessageConverter() {
@ -58,7 +59,6 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* Construct an {@code AbstractHttpMessageConverter} with one supported media type.
*
* @param supportedMediaType the supported media type
*/
protected AbstractHttpMessageConverter(MediaType supportedMediaType) {
@ -67,14 +67,16 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* Construct an {@code AbstractHttpMessageConverter} with multiple supported media type.
*
* @param supportedMediaTypes the supported media types
*/
protected AbstractHttpMessageConverter(MediaType... supportedMediaTypes) {
setSupportedMediaTypes(Arrays.asList(supportedMediaTypes));
}
/** Set the list of {@link MediaType} objects supported by this converter. */
/**
* Set the list of {@link MediaType} objects supported by this converter.
*/
public void setSupportedMediaTypes(List<MediaType> supportedMediaTypes) {
Assert.notEmpty(supportedMediaTypes, "'supportedMediaTypes' must not be empty");
this.supportedMediaTypes = new ArrayList<MediaType>(supportedMediaTypes);
@ -84,21 +86,20 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
return Collections.unmodifiableList(this.supportedMediaTypes);
}
/**
* {@inheritDoc}
*
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported}, and if the {@linkplain
* #getSupportedMediaTypes() supported media types} {@linkplain MediaType#includes(MediaType) include} the given media
* type.
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported},
* and if the {@linkplain #getSupportedMediaTypes() supported media types}
* {@linkplain MediaType#includes(MediaType) include} the given media type.
*/
public boolean canRead(Class<?> clazz, MediaType mediaType) {
return supports(clazz) && canRead(mediaType);
}
/**
* Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types} include the given media
* type.
*
* Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types}
* include the given media type.
* @param mediaType the media type
* @return true if the supported media types include the media type, or if the media type is {@code null}
*/
@ -116,10 +117,9 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* {@inheritDoc}
*
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported}, and if the {@linkplain
* #getSupportedMediaTypes() supported media types} {@linkplain MediaType#includes(MediaType) include} the given media
* type.
* <p>This implementation checks if the given class is {@linkplain #supports(Class) supported},
* and if the {@linkplain #getSupportedMediaTypes() supported media types}
* {@linkplain MediaType#includes(MediaType) include} the given media type.
*/
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return supports(clazz) && canWrite(mediaType);
@ -128,7 +128,6 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* Returns true if the given media type includes any of the
* {@linkplain #setSupportedMediaTypes(List) supported media types}.
*
* @param mediaType the media type
* @return true if the supported media types include the media type, or if the media type is {@code null}
*/
@ -144,45 +143,24 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
return false;
}
/**
* Indicates whether the given class is supported by this converter.
*
* @param clazz the class to test for support
* @return <code>true</code> if supported; <code>false</code> otherwise
*/
protected abstract boolean supports(Class<?> clazz);
/**
* {@inheritDoc}
*
* <p>This implementation simple delegates to {@link #readInternal(Class, HttpInputMessage)}. Future implementations
* might add some default behavior, however.
* <p>This implementation simple delegates to {@link #readInternal(Class, HttpInputMessage)}.
* Future implementations might add some default behavior, however.
*/
public final T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException {
public final T read(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
return readInternal(clazz, inputMessage);
}
/**
* Abstract template method that reads the actualy object. Invoked from {@link #read(Class, HttpInputMessage)}.
*
* @param clazz the type of object to return
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
*/
protected abstract T readInternal(Class<T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/**
* {@inheritDoc}
*
* <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content type was not provided, calls
* {@link #getContentLength}, and sets the corresponding headers on the output message. It then calls {@link
* #writeInternal}.
* <p>This implementation delegates to {@link #getDefaultContentType(Object)} if a content
* type was not provided, calls {@link #getContentLength}, and sets the corresponding headers
* on the output message. It then calls {@link #writeInternal}.
*/
public final void write(T t, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
HttpHeaders headers = outputMessage.getHeaders();
if (contentType == null || contentType.isWildcardType() || contentType.isWildcardSubtype()) {
contentType = getDefaultContentType(t);
@ -199,12 +177,11 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
}
/**
* Returns the default content type for the given type. Called when {@link #write} is invoked without a specified
* content type parameter.
*
* <p>By default, this returns the first element of the {@link #setSupportedMediaTypes(List) supportedMediaTypes}
* property, if any. Can be overriden in subclasses.
*
* Returns the default content type for the given type. Called when {@link #write}
* is invoked without a specified content type parameter.
* <p>By default, this returns the first element of the
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} property, if any.
* Can be overridden in subclasses.
* @param t the type to return the content type for
* @return the content type, or <code>null</code> if not known
*/
@ -215,10 +192,8 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* Returns the content length for the given type.
*
* <p>By default, this returns {@code null}, meaning that the content length is unknown. Can be overriden in
* subclasses.
*
* <p>By default, this returns {@code null}, meaning that the content length is unknown.
* Can be overridden in subclasses.
* @param t the type to return the content length for
* @return the content length, or {@code null} if not known
*/
@ -226,9 +201,27 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
return null;
}
/**
* Indicates whether the given class is supported by this converter.
* @param clazz the class to test for support
* @return <code>true</code> if supported; <code>false</code> otherwise
*/
protected abstract boolean supports(Class<?> clazz);
/**
* Abstract template method that reads the actualy object. Invoked from {@link #read}.
* @param clazz the type of object to return
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
*/
protected abstract T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/**
* Abstract template method that writes the actual body. Invoked from {@link #write}.
*
* @param t the object to write to the output message
* @param outputMessage the message to write to
* @throws IOException in case of I/O errors

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -62,37 +62,27 @@ import org.springframework.util.Assert;
*/
public class BufferedImageHttpMessageConverter implements HttpMessageConverter<BufferedImage> {
private List<MediaType> readableMediaTypes = new ArrayList<MediaType>();
private final List<MediaType> readableMediaTypes = new ArrayList<MediaType>();
private MediaType defaultContentType;
private File cacheDir;
public BufferedImageHttpMessageConverter() {
String[] readerMediaTypes = ImageIO.getReaderMIMETypes();
for (String mediaType : readerMediaTypes) {
readableMediaTypes.add(MediaType.parseMediaType(mediaType));
this.readableMediaTypes.add(MediaType.parseMediaType(mediaType));
}
String[] writerMediaTypes = ImageIO.getWriterMIMETypes();
if (writerMediaTypes.length > 0) {
defaultContentType = MediaType.parseMediaType(writerMediaTypes[0]);
this.defaultContentType = MediaType.parseMediaType(writerMediaTypes[0]);
}
}
/**
* Returns the default {@code Content-Type} to be used for writing. Called when {@link #write} is invoked without a
* specified content type parameter.
*
* @return the default content type
*/
public MediaType getDefaultContentType() {
return defaultContentType;
}
/**
* Sets the default {@code Content-Type} to be used for writing.
*
* @throws IllegalArgumentException if the given content type is not supported by the Java Image I/O API
*/
public void setDefaultContentType(MediaType defaultContentType) {
@ -106,20 +96,27 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
this.defaultContentType = defaultContentType;
}
/** Sets the cache directory. If this property is set to an existing directory, this converter will cache image data. */
/**
* Returns the default {@code Content-Type} to be used for writing.
* Called when {@link #write} is invoked without a specified content type parameter.
*/
public MediaType getDefaultContentType() {
return this.defaultContentType;
}
/**
* Sets the cache directory. If this property is set to an existing directory,
* this converter will cache image data.
*/
public void setCacheDir(File cacheDir) {
Assert.notNull(cacheDir, "'cacheDir' must not be null");
Assert.isTrue(cacheDir.isDirectory(), "'cacheDir' is not a directory");
this.cacheDir = cacheDir;
}
public boolean canRead(Class<?> clazz, MediaType mediaType) {
if (BufferedImage.class.equals(clazz)) {
return isReadable(mediaType);
}
else {
return false;
}
return (BufferedImage.class.equals(clazz) && isReadable(mediaType));
}
private boolean isReadable(MediaType mediaType) {
@ -131,12 +128,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
if (BufferedImage.class.equals(clazz)) {
return isWritable(mediaType);
}
else {
return false;
}
return (BufferedImage.class.equals(clazz) && isWritable(mediaType));
}
private boolean isWritable(MediaType mediaType) {
@ -148,11 +140,12 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
public List<MediaType> getSupportedMediaTypes() {
return Collections.unmodifiableList(readableMediaTypes);
return Collections.unmodifiableList(this.readableMediaTypes);
}
public BufferedImage read(Class<BufferedImage> clazz, HttpInputMessage inputMessage)
public BufferedImage read(Class<? extends BufferedImage> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
ImageInputStream imageInputStream = null;
ImageReader imageReader = null;
try {
@ -187,7 +180,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
private ImageInputStream createImageInputStream(InputStream is) throws IOException {
if (cacheDir != null) {
if (this.cacheDir != null) {
return new FileCacheImageInputStream(is, cacheDir);
}
else {
@ -197,6 +190,7 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
public void write(BufferedImage image, MediaType contentType, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
if (contentType == null) {
contentType = getDefaultContentType();
}
@ -236,17 +230,17 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
}
private ImageOutputStream createImageOutputStream(OutputStream os) throws IOException {
if (cacheDir != null) {
return new FileCacheImageOutputStream(os, cacheDir);
if (this.cacheDir != null) {
return new FileCacheImageOutputStream(os, this.cacheDir);
}
else {
return new MemoryCacheImageOutputStream(os);
}
}
/**
* Template method that allows for manipulating the {@link ImageReadParam} before it is used to read an image.
*
* <p>Default implementation is empty.
*/
protected void process(ImageReadParam irp) {
@ -254,9 +248,9 @@ public class BufferedImageHttpMessageConverter implements HttpMessageConverter<B
/**
* Template method that allows for manipulating the {@link ImageWriteParam} before it is used to write an image.
*
* <p>Default implementation is empty.
*/
protected void process(ImageWriteParam iwp) {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -47,7 +47,7 @@ public class ByteArrayHttpMessageConverter extends AbstractHttpMessageConverter<
}
@Override
public byte[] readInternal(Class<byte[]> clazz, HttpInputMessage inputMessage) throws IOException {
public byte[] readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
long contentLength = inputMessage.getHeaders().getContentLength();
if (contentLength >= 0) {
ByteArrayOutputStream bos = new ByteArrayOutputStream((int) contentLength);

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -50,19 +50,20 @@ public class FormHttpMessageConverter extends AbstractHttpMessageConverter<Multi
public static final Charset DEFAULT_CHARSET = Charset.forName(WebUtils.DEFAULT_CHARACTER_ENCODING);
/** Creates a new instance of the {@code FormHttpMessageConverter}. */
public FormHttpMessageConverter() {
super(new MediaType("application", "x-www-form-urlencoded"));
}
@Override
public boolean supports(Class<?> clazz) {
return MultiValueMap.class.isAssignableFrom(clazz);
}
@Override
public MultiValueMap<String, String> readInternal(Class<MultiValueMap<String, String>> clazz,
HttpInputMessage inputMessage) throws IOException {
public MultiValueMap<String, String> readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
String body = FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));
@ -112,4 +113,5 @@ public class FormHttpMessageConverter extends AbstractHttpMessageConverter<Multi
}
FileCopyUtils.copy(builder.toString(), new OutputStreamWriter(outputMessage.getBody(), charset));
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -27,6 +27,7 @@ import org.springframework.http.MediaType;
* Strategy interface that specifies a converter that can convert from and to HTTP requests and responses.
*
* @author Arjen Poutsma
* @author Juergen Hoeller
* @since 3.0
*/
public interface HttpMessageConverter<T> {
@ -55,23 +56,24 @@ public interface HttpMessageConverter<T> {
/**
* Read an object of the given type form the given input message, and returns it.
* @param clazz the type of object to return. This type must have previously been passed to the {@link #canRead
* canRead} method of this interface, which must have returned {@code true}.
* @param clazz the type of object to return. This type must have previously been passed to the
* {@link #canRead canRead} method of this interface, which must have returned {@code true}.
* @param inputMessage the HTTP input message to read from
* @return the converted object
* @throws IOException in case of I/O errors
* @throws HttpMessageNotReadableException in case of conversion errors
*/
T read(Class<T> clazz, HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException;
T read(Class<? extends T> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException;
/**
* Write an given object to the given output message.
*
* @param t the object to write to the output message. The type of this object must have previously been passed to the
* {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param contentType the content type to use when writing. May be {@code null} to indicate that the the default
* content type of the converter must be used. If not {@code null}, this media type must have previously been passed to
* the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param t the object to write to the output message. The type of this object must have previously been
* passed to the {@link #canWrite canWrite} method of this interface, which must have returned {@code true}.
* @param contentType the content type to use when writing. May be {@code null} to indicate that the
* default content type of the converter must be used. If not {@code null}, this media type must have
* previously been passed to the {@link #canWrite canWrite} method of this interface, which must have
* returned {@code true}.
* @param outputMessage the message to write to
* @throws IOException in case of I/O errors
* @throws HttpMessageNotWritableException in case of conversion errors

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -56,7 +56,7 @@ public class StringHttpMessageConverter extends AbstractHttpMessageConverter<Str
}
@Override
public String readInternal(Class<String> clazz, HttpInputMessage inputMessage) throws IOException {
protected String readInternal(Class clazz, HttpInputMessage inputMessage) throws IOException {
MediaType contentType = inputMessage.getHeaders().getContentType();
Charset charset = contentType.getCharSet() != null ? contentType.getCharSet() : DEFAULT_CHARSET;
return FileCopyUtils.copyToString(new InputStreamReader(inputMessage.getBody(), charset));

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -35,18 +35,17 @@ import org.springframework.http.converter.HttpMessageNotWritableException;
import org.springframework.util.Assert;
/**
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter} that can read
* and write JSON using <a href="http://jackson.codehaus.org/">Jackson's</a> {@link ObjectMapper}.
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverter}
* that can read and write JSON using <a href="http://jackson.codehaus.org/">Jackson's</a> {@link ObjectMapper}.
*
* <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
* #setSupportedMediaTypes(List) supportedMediaTypes} property.
* method.
* <p>By default, this converter supports {@code application/json}. This can be overridden by setting the
* {@link #setSupportedMediaTypes(List) supportedMediaTypes} property.
*
* @author Arjen Poutsma
* @see org.springframework.web.servlet.view.json.BindingJacksonJsonView
* @since 3.0
* @see org.springframework.web.servlet.view.json.BindingJacksonJsonView
*/
public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConverter<Object> {
@ -56,15 +55,17 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
private boolean prefixJson = false;
/** Construct a new {@code BindingJacksonHttpMessageConverter}, */
/**
* Construct a new {@code BindingJacksonHttpMessageConverter}.
*/
public MappingJacksonHttpMessageConverter() {
super(new MediaType("application", "json", DEFAULT_CHARSET));
}
/**
* Sets the {@code ObjectMapper} for this view. If not set, a default {@link ObjectMapper#ObjectMapper() ObjectMapper}
* is used.
*
* Sets the {@code ObjectMapper} for this view. 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 of the JSON serialization
* process. For example, an extended {@link org.codehaus.jackson.map.SerializerFactory} can be configured that provides
* custom serializers for specific types. The other option for refining the serialization process is to use Jackson's
@ -77,7 +78,6 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
/**
* Indicates whether the JSON output by this view should be prefixed with "{} &&". Default is false.
*
* <p> Prefixing the JSON string in this manner is used to help prevent JSON Hijacking. The prefix renders the string
* syntactically invalid as a script so that it cannot be hijacked. 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.
@ -86,39 +86,42 @@ public class MappingJacksonHttpMessageConverter extends AbstractHttpMessageConve
this.prefixJson = prefixJson;
}
@Override
public boolean canRead(Class<?> clazz, MediaType mediaType) {
JavaType javaType = TypeFactory.fromClass(clazz);
return objectMapper.canDeserialize(javaType) && canRead(mediaType);
return this.objectMapper.canDeserialize(javaType) && canRead(mediaType);
}
@Override
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return objectMapper.canSerialize(clazz) && canWrite(mediaType);
return this.objectMapper.canSerialize(clazz) && canWrite(mediaType);
}
@Override
protected boolean supports(Class<?> clazz) {
// should not be called, since we override canRead/Write
// should not be called, since we override canRead/Write instead
throw new UnsupportedOperationException();
}
@Override
protected Object readInternal(Class<Object> clazz, HttpInputMessage inputMessage)
protected Object readInternal(Class<?> clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
return objectMapper.readValue(inputMessage.getBody(), clazz);
return this.objectMapper.readValue(inputMessage.getBody(), clazz);
}
@Override
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) {
this.objectMapper.getJsonFactory().createJsonGenerator(outputMessage.getBody(), encoding);
if (this.prefixJson) {
jsonGenerator.writeRaw("{} && ");
}
objectMapper.writeValue(jsonGenerator, o);
this.objectMapper.writeValue(jsonGenerator, o);
}
private JsonEncoding getEncoding(MediaType contentType) {

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -19,7 +19,6 @@ package org.springframework.http.converter.xml;
import java.io.IOException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
@ -33,8 +32,8 @@ import org.springframework.http.converter.AbstractHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConversionException;
/**
* Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters} that
* convert from/to XML.
* Abstract base class for {@link org.springframework.http.converter.HttpMessageConverter HttpMessageConverters}
* that convert from/to XML.
*
* <p>By default, subclasses of this converter support {@code text/xml}, {@code application/xml}, and {@code
* application/*-xml}. This can be overridden by setting the {@link #setSupportedMediaTypes(java.util.List)
@ -47,58 +46,58 @@ public abstract class AbstractXmlHttpMessageConverter<T> extends AbstractHttpMes
private final TransformerFactory transformerFactory = TransformerFactory.newInstance();
/**
* Protected constructor that sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes} to {@code
* text/xml} and {@code application/xml}, and {@code application/*-xml}.
* Protected constructor that sets the {@link #setSupportedMediaTypes(java.util.List) supportedMediaTypes}
* to {@code text/xml} and {@code application/xml}, and {@code application/*-xml}.
*/
protected AbstractXmlHttpMessageConverter() {
super(new MediaType("application", "xml"), new MediaType("text", "xml"), new MediaType("application", "*+xml"));
}
/** Invokes {@link #readFromSource(Class, HttpHeaders, Source)}. */
@Override
public final T readInternal(Class<T> clazz, HttpInputMessage inputMessage) throws IOException {
public final T readInternal(Class<? extends T> clazz, HttpInputMessage inputMessage) throws IOException {
return readFromSource(clazz, inputMessage.getHeaders(), new StreamSource(inputMessage.getBody()));
}
/**
* Abstract template method called from {@link #read(Class, HttpInputMessage)}.
*
* @param clazz the type of object to return
* @param headers the HTTP input headers
* @param source the HTTP input body
* @return the converted object
* @throws IOException in case of I/O errors
* @throws org.springframework.http.converter.HttpMessageConversionException in case of conversion errors
*/
protected abstract T readFromSource(Class<T> clazz, HttpHeaders headers, Source source) throws IOException;
@Override
protected final void writeInternal(T t, HttpOutputMessage outputMessage) throws IOException {
writeToResult(t, outputMessage.getHeaders(), new StreamResult(outputMessage.getBody()));
}
/**
* Transforms the given {@code Source} to the {@code Result}.
* @param source the source to transform from
* @param result the result to transform to
* @throws HttpMessageConversionException in case of transformation errors
*/
protected void transform(Source source, Result result) throws TransformerException {
this.transformerFactory.newTransformer().transform(source, result);
}
/**
* Abstract template method called from {@link #read(Class, HttpInputMessage)}.
* @param clazz the type of object to return
* @param headers the HTTP input headers
* @param source the HTTP input body
* @return the converted object
* @throws IOException in case of I/O errors
* @throws org.springframework.http.converter.HttpMessageConversionException in case of conversion errors
*/
protected abstract T readFromSource(Class<? extends T> clazz, HttpHeaders headers, Source source)
throws IOException;
/**
* Abstract template method called from {@link #writeInternal(Object, HttpOutputMessage)}.
*
* @param t the object to write to the output message
* @param headers the HTTP output headers
* @param result the HTTP output body
* @throws IOException in case of I/O errors
* @throws HttpMessageConversionException in case of conversion errors
*/
protected abstract void writeToResult(T t, HttpHeaders headers, Result result) throws IOException;
/**
* Transforms the given {@code Source} to the {@code Result}.
*
* @param source the source to transform from
* @param result the result to transform to
* @throws HttpMessageConversionException in case of transformation errors
*/
protected void transform(Source source, Result result) throws TransformerException {
Transformer transformer = transformerFactory.newTransformer();
transformer.transform(source, result);
}
protected abstract void writeToResult(T t, HttpHeaders headers, Result result)
throws IOException;
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -67,14 +67,14 @@ public class Jaxb2RootElementHttpMessageConverter extends AbstractJaxb2HttpMessa
}
@Override
protected Object readFromSource(Class<Object> clazz, HttpHeaders headers, Source source) throws IOException {
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException {
try {
Unmarshaller unmarshaller = createUnmarshaller(clazz);
if (clazz.isAnnotationPresent(XmlRootElement.class)) {
return unmarshaller.unmarshal(source);
}
else {
JAXBElement<Object> jaxbElement = unmarshaller.unmarshal(source, clazz);
JAXBElement jaxbElement = unmarshaller.unmarshal(source, clazz);
return jaxbElement.getValue();
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -49,6 +49,7 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
private Unmarshaller unmarshaller;
/**
* Construct a new {@code MarshallingHttpMessageConverter} with no {@link Marshaller} or {@link Unmarshaller} set. The
* marshaller and unmarshaller must be set after construction by invoking {@link #setMarshaller(Marshaller)} and {@link
@ -62,7 +63,6 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
* Marshaller} also implements the {@link Unmarshaller} interface, it is used for both marshalling and unmarshalling.
* Otherwise, an exception is thrown. <p>Note that all {@code Marshaller} implementations in Spring also implement the
* {@code Unmarshaller} interface, so that you can safely use this constructor.
*
* @param marshaller object used as marshaller and unmarshaller
*/
public MarshallingHttpMessageConverter(Marshaller marshaller) {
@ -76,7 +76,6 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
/**
* Construct a new <code>MarshallingMessageConverter</code> with the given {@code Marshaller} and {@code
* Unmarshaller}.
*
* @param marshaller the Marshaller to use
* @param unmarshaller the Unmarshaller to use
*/
@ -87,26 +86,31 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
this.unmarshaller = unmarshaller;
}
/** Set the {@link Marshaller} to be used by this message converter. */
/**
* Set the {@link Marshaller} to be used by this message converter.
*/
public void setMarshaller(Marshaller marshaller) {
this.marshaller = marshaller;
}
/** Set the {@link Unmarshaller} to be used by this message converter. */
/**
* Set the {@link Unmarshaller} to be used by this message converter.
*/
public void setUnmarshaller(Unmarshaller unmarshaller) {
this.unmarshaller = unmarshaller;
}
@Override
public boolean supports(Class<?> clazz) {
return unmarshaller.supports(clazz);
return this.unmarshaller.supports(clazz);
}
@Override
protected Object readFromSource(Class<Object> clazz, HttpHeaders headers, Source source) throws IOException {
protected Object readFromSource(Class<?> clazz, HttpHeaders headers, Source source) throws IOException {
Assert.notNull(this.unmarshaller, "Property 'unmarshaller' is required");
try {
return unmarshaller.unmarshal(source);
return this.unmarshaller.unmarshal(source);
}
catch (UnmarshallingFailureException ex) {
throw new HttpMessageNotReadableException("Could not read [" + clazz + "]", ex);
@ -117,10 +121,11 @@ public class MarshallingHttpMessageConverter extends AbstractXmlHttpMessageConve
protected void writeToResult(Object o, HttpHeaders headers, Result result) throws IOException {
Assert.notNull(this.marshaller, "Property 'marshaller' is required");
try {
marshaller.marshal(o, result);
this.marshaller.marshal(o, result);
}
catch (MarshallingFailureException ex) {
throw new HttpMessageNotWritableException("Could not write [" + o + "]", ex);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -36,8 +36,8 @@ import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.http.converter.HttpMessageNotWritableException;
/**
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter} that can read and write {@link
* Source} objects.
* Implementation of {@link org.springframework.http.converter.HttpMessageConverter}
* that can read and write {@link Source} objects.
*
* @author Arjen Poutsma
* @since 3.0
@ -52,7 +52,7 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHtt
@Override
@SuppressWarnings("unchecked")
protected T readFromSource(Class<T> clazz, HttpHeaders headers, Source source) throws IOException {
protected T readFromSource(Class clazz, HttpHeaders headers, Source source) throws IOException {
try {
if (DOMSource.class.equals(clazz)) {
DOMResult domResult = new DOMResult();
@ -93,4 +93,5 @@ public class SourceHttpMessageConverter<T extends Source> extends AbstractXmlHtt
throw new HttpMessageNotWritableException("Could not transform [" + t + "] to [" + result + "]", ex);
}
}
}

View File

@ -17,10 +17,17 @@
package org.springframework.http.converter;
import java.io.IOException;
import java.io.StringReader;
import java.io.StringWriter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.namespace.QName;
import org.junit.Before;
import org.junit.Test;
import static org.junit.Assert.*;
import org.junit.Test;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.HttpOutputMessage;
@ -79,7 +86,7 @@ public class HttpMessageConverterTests {
}
@Override
protected T readInternal(Class<T> clazz, HttpInputMessage inputMessage)
protected T readInternal(Class clazz, HttpInputMessage inputMessage)
throws IOException, HttpMessageNotReadableException {
fail("Not expected");
return null;
@ -95,4 +102,5 @@ public class HttpMessageConverterTests {
private static class MyType {
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2009 the original author or authors.
* Copyright 2002-2010 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -31,7 +31,9 @@ import org.springframework.http.MediaType;
import org.springframework.http.MockHttpInputMessage;
import org.springframework.http.MockHttpOutputMessage;
/** @author Arjen Poutsma */
/**
* @author Arjen Poutsma
*/
public class MappingJacksonHttpMessageConverterTests {
private MappingJacksonHttpMessageConverter converter;
@ -60,7 +62,7 @@ public class MappingJacksonHttpMessageConverterTests {
"{\"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 = (MyBean) converter.read((Class) MyBean.class, inputMessage);
MyBean result = (MyBean) converter.read(MyBean.class, inputMessage);
assertEquals("Foo", result.getString());
assertEquals(42, result.getNumber());
assertEquals(42F, result.getFraction(), 0F);
@ -76,7 +78,7 @@ public class MappingJacksonHttpMessageConverterTests {
"{\"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<String, Object> result = (HashMap<String, Object>) converter.read((Class)HashMap.class, inputMessage);
HashMap<String, Object> result = (HashMap<String, Object>) converter.read(HashMap.class, inputMessage);
assertEquals("Foo", result.get("string"));
assertEquals(42, result.get("number"));
assertEquals(42D, (Double) result.get("fraction"), 0D);