SPR-6970 - AbstractHttpMessageConverter canWrite logic the wrong way round??

This commit is contained in:
Arjen Poutsma
2010-03-12 16:43:57 +00:00
parent 4c4f19ec94
commit 85b8befbd1
6 changed files with 122 additions and 29 deletions

View File

@@ -366,17 +366,21 @@ public class MediaType implements Comparable<MediaType> {
* Indicate whether this {@link MediaType} includes the given media type.
*
* <p>For instance, {@code text/*} includes {@code text/plain}, {@code text/html}, and {@code application/*+xml}
* includes {@code application/soap+xml}, etc.
* includes {@code application/soap+xml}, etc. This method is non-symmetic.
*
* @param other the reference media type with which to compare
* @return <code>true</code> if this media type includes the given media type; <code>false</code> otherwise
*/
public boolean includes(MediaType other) {
if (this == other) {
if (other == null) {
return false;
}
if (this.isWildcardType()) {
// */* includes anything
return true;
}
if (this.type.equals(other.type)) {
if (this.subtype.equals(other.subtype) || isWildcardSubtype()) {
else if (this.type.equals(other.type)) {
if (this.subtype.equals(other.subtype) || this.isWildcardSubtype()) {
return true;
}
// application/*+xml includes application/soap+xml
@@ -392,7 +396,46 @@ public class MediaType implements Comparable<MediaType> {
}
}
}
return isWildcardType();
return false;
}
/**
* Indicate whether this {@link MediaType} is compatible with the given media type.
*
* <p>For instance, {@code text/*} is compatible with {@code text/plain}, {@code text/html}, and vice versa. In
* effect, this method is similar to {@link #includes(MediaType)}, except that it's symmetric.
*
* @param other the reference media type with which to compare
* @return <code>true</code> if this media type is compatible with the given media type; <code>false</code> otherwise
*/
public boolean isCompatibleWith(MediaType other) {
if (other == null) {
return false;
}
if (isWildcardType() || other.isWildcardType()) {
return true;
}
else if (this.type.equals(other.type)) {
if (this.subtype.equals(other.subtype) || this.isWildcardSubtype() || other.isWildcardSubtype()) {
return true;
}
// application/*+xml is compatible with application/soap+xml, and vice-versa
int thisPlusIdx = this.subtype.indexOf('+');
int otherPlusIdx = other.subtype.indexOf('+');
if (thisPlusIdx != -1 && otherPlusIdx != -1) {
String thisSubtypeNoSuffix = this.subtype.substring(0, thisPlusIdx);
String otherSubtypeNoSuffix = other.subtype.substring(0, otherPlusIdx);
String thisSubtypeSuffix = this.subtype.substring(thisPlusIdx + 1);
String otherSubtypeSuffix = other.subtype.substring(otherPlusIdx + 1);
if (thisSubtypeSuffix.equals(otherSubtypeSuffix) &&
(WILDCARD_TYPE.equals(thisSubtypeNoSuffix) || WILDCARD_TYPE.equals(otherSubtypeNoSuffix))) {
return true;
}
}
}
return false;
}
/**

View File

@@ -100,7 +100,8 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
/**
* Returns true if any of the {@linkplain #setSupportedMediaTypes(List) supported media types}
* include the given media type.
* @param mediaType the media type
* @param mediaType the media type to read, can be {@code null} if not specified. Typically the value of a
* {@code Content-Type} header.
* @return true if the supported media types include the media type, or if the media type is {@code null}
*/
protected boolean canRead(MediaType mediaType) {
@@ -123,20 +124,21 @@ public abstract class AbstractHttpMessageConverter<T> implements HttpMessageConv
*/
public boolean canWrite(Class<?> clazz, MediaType mediaType) {
return supports(clazz) && canWrite(mediaType);
}
}
/**
* 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}
* @param mediaType the media type to write, can be {@code null} if not specified. Typically the value of an
* {@code Accept} header.
* @return true if the supported media types are compatible with the media type, or if the media type is {@code null}
*/
protected boolean canWrite(MediaType mediaType) {
if (mediaType == null) {
if (mediaType == null || MediaType.ALL.equals(mediaType)) {
return true;
}
for (MediaType supportedMediaType : getSupportedMediaTypes()) {
if (mediaType.includes(supportedMediaType)) {
if (supportedMediaType.isCompatibleWith(mediaType)) {
return true;
}
}

View File

@@ -138,8 +138,8 @@ public class FormHttpMessageConverter implements HttpMessageConverter<MultiValue
return false;
}
if (mediaType != null) {
return mediaType.includes(MediaType.APPLICATION_FORM_URLENCODED) ||
mediaType.includes(MediaType.MULTIPART_FORM_DATA);
return mediaType.isCompatibleWith(MediaType.APPLICATION_FORM_URLENCODED) ||
mediaType.isCompatibleWith(MediaType.MULTIPART_FORM_DATA);
}
else {
return true;

View File

@@ -35,16 +35,18 @@ public interface HttpMessageConverter<T> {
/**
* Indicates whether the given class can be read by this converter.
* @param clazz the class to test for readability
* @param mediaType the media type to read, can be {@code null} if not specified
* @return <code>true</code> if readable; <code>false</code> otherwise
* @param mediaType the media type to read, can be {@code null} if not specified. Typically the value of a
* {@code Content-Type} header.
* @return {@code true} if readable; {@code false} otherwise
*/
boolean canRead(Class<?> clazz, MediaType mediaType);
/**
* Indicates whether the given class can be written by this converter.
* @param clazz the class to test for writability
* @param mediaType the media type to write, can be {@code null} if not specified
* @return <code>true</code> if writable; <code>false</code> otherwise
* @param mediaType the media type to write, can be {@code null} if not specified. Typically the value of an
* {@code Accept} header.
* @return {@code true} if writable; {@code false} otherwise
*/
boolean canWrite(Class<?> clazz, MediaType mediaType);