Support for media subtype suffixes in include(), i.e. application/*+xml includes application/soap+xml
This commit is contained in:
parent
8259d45583
commit
8546e64b03
|
|
@ -34,14 +34,14 @@ import org.springframework.util.StringUtils;
|
||||||
/**
|
/**
|
||||||
* Represents an Internet Media Type, as defined in the HTTP specification.
|
* Represents an Internet Media Type, as defined in the HTTP specification.
|
||||||
*
|
*
|
||||||
* <p>Consists of a {@linkplain #getType() type} and a {@linkplain #getSubtype() subtype}.
|
* <p>Consists of a {@linkplain #getType() type} and a {@linkplain #getSubtype() subtype}. Also has functionality to
|
||||||
* Also has functionality to parse media types from a string using {@link #parseMediaType(String)},
|
* parse media types from a string using {@link #parseMediaType(String)}, or multiple comma-separated media types using
|
||||||
* or multiple comma-separated media types using {@link #parseMediaTypes(String)}.
|
* {@link #parseMediaTypes(String)}.
|
||||||
*
|
*
|
||||||
* @author Arjen Poutsma
|
* @author Arjen Poutsma
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @since 3.0
|
|
||||||
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">HTTP 1.1</a>
|
* @see <a href="http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.7">HTTP 1.1</a>
|
||||||
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
public class MediaType implements Comparable<MediaType> {
|
public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
|
|
@ -53,17 +53,16 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
private static final String PARAM_CHARSET = "charset";
|
private static final String PARAM_CHARSET = "charset";
|
||||||
|
|
||||||
|
|
||||||
private final String type;
|
private final String type;
|
||||||
|
|
||||||
private final String subtype;
|
private final String subtype;
|
||||||
|
|
||||||
private final Map<String, String> parameters;
|
private final Map<String, String> parameters;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MediaType} for the given primary type.
|
* Create a new {@link MediaType} for the given primary type. <p>The {@linkplain #getSubtype() subtype} is set to
|
||||||
* <p>The {@linkplain #getSubtype() subtype} is set to <code>*</code>, parameters empty.
|
* <code>*</code>, parameters empty.
|
||||||
|
*
|
||||||
* @param type the primary type
|
* @param type the primary type
|
||||||
*/
|
*/
|
||||||
public MediaType(String type) {
|
public MediaType(String type) {
|
||||||
|
|
@ -71,8 +70,8 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MediaType} for the given primary type and subtype.
|
* Create a new {@link MediaType} for the given primary type and subtype. <p>The parameters are empty.
|
||||||
* <p>The parameters are empty.
|
*
|
||||||
* @param type the primary type
|
* @param type the primary type
|
||||||
* @param subtype the subtype
|
* @param subtype the subtype
|
||||||
*/
|
*/
|
||||||
|
|
@ -82,6 +81,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MediaType} for the given type, subtype, and character set.
|
* Create a new {@link MediaType} for the given type, subtype, and character set.
|
||||||
|
*
|
||||||
* @param type the primary type
|
* @param type the primary type
|
||||||
* @param subtype the subtype
|
* @param subtype the subtype
|
||||||
* @param charSet the character set
|
* @param charSet the character set
|
||||||
|
|
@ -92,6 +92,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new {@link MediaType} for the given type, subtype, and parameters.
|
* Create a new {@link MediaType} for the given type, subtype, and parameters.
|
||||||
|
*
|
||||||
* @param type the primary type
|
* @param type the primary type
|
||||||
* @param subtype the subtype
|
* @param subtype the subtype
|
||||||
* @param parameters the parameters, mat be <code>null</code>
|
* @param parameters the parameters, mat be <code>null</code>
|
||||||
|
|
@ -110,30 +111,24 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Return the primary type. */
|
||||||
/**
|
|
||||||
* Return the primary type.
|
|
||||||
*/
|
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return this.type;
|
return this.type;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Indicate whether the {@linkplain #getType() type} is the wildcard character <code>*</code> or not. */
|
||||||
* Indicate whether the {@linkplain #getType() type} is the wildcard character <code>*</code> or not.
|
|
||||||
*/
|
|
||||||
public boolean isWildcardType() {
|
public boolean isWildcardType() {
|
||||||
return WILDCARD_TYPE.equals(type);
|
return WILDCARD_TYPE.equals(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/** Return the subtype. */
|
||||||
* Return the subtype.
|
|
||||||
*/
|
|
||||||
public String getSubtype() {
|
public String getSubtype() {
|
||||||
return this.subtype;
|
return this.subtype;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate whether the {@linkplain #getSubtype() subtype} is the wildcard character <code>*</code> or not.
|
* Indicate whether the {@linkplain #getSubtype() subtype} is the wildcard character <code>*</code> or not.
|
||||||
|
*
|
||||||
* @return whether the subtype is <code>*</code>
|
* @return whether the subtype is <code>*</code>
|
||||||
*/
|
*/
|
||||||
public boolean isWildcardSubtype() {
|
public boolean isWildcardSubtype() {
|
||||||
|
|
@ -142,6 +137,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the character set, as indicated by a <code>charset</code> parameter, if any.
|
* Return the character set, as indicated by a <code>charset</code> parameter, if any.
|
||||||
|
*
|
||||||
* @return the character set; or <code>null</code> if not available
|
* @return the character set; or <code>null</code> if not available
|
||||||
*/
|
*/
|
||||||
public Charset getCharSet() {
|
public Charset getCharSet() {
|
||||||
|
|
@ -151,6 +147,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the quality value, as indicated by a <code>q</code> parameter, if any. Defaults to <code>1.0</code>.
|
* Return the quality value, as indicated by a <code>q</code> parameter, if any. Defaults to <code>1.0</code>.
|
||||||
|
*
|
||||||
* @return the quality factory
|
* @return the quality factory
|
||||||
*/
|
*/
|
||||||
public double getQualityValue() {
|
public double getQualityValue() {
|
||||||
|
|
@ -160,6 +157,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a generic parameter value, given a parameter name.
|
* Return a generic parameter value, given a parameter name.
|
||||||
|
*
|
||||||
* @param name the parameter name
|
* @param name the parameter name
|
||||||
* @return the parameter value; or <code>null</code> if not present
|
* @return the parameter value; or <code>null</code> if not present
|
||||||
*/
|
*/
|
||||||
|
|
@ -167,11 +165,10 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
return this.parameters.get(name);
|
return this.parameters.get(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Indicate whether this {@link MediaType} includes the given media type.
|
* Indicate whether this {@link MediaType} includes the given media type. <p>For instance, {@code text/*} includes
|
||||||
* <p>For instance, <code>text/*</code> includes <code>text/plain</code>,
|
* {@code text/plain}, {@code text/html}, and {@code application/*+xml} includes {@code application/soap+xml}, etc.
|
||||||
* <code>text/html</code>, etc.
|
*
|
||||||
* @param other the reference media type with which to compare
|
* @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
|
* @return <code>true</code> if this media type includes the given media type; <code>false</code> otherwise
|
||||||
*/
|
*/
|
||||||
|
|
@ -183,6 +180,18 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
if (this.subtype.equals(other.subtype) || isWildcardSubtype()) {
|
if (this.subtype.equals(other.subtype) || isWildcardSubtype()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
// application/*+xml includes application/soap+xml
|
||||||
|
int thisPlusIdx = this.subtype.indexOf('+');
|
||||||
|
int otherPlusIdx = other.subtype.indexOf('+');
|
||||||
|
if (thisPlusIdx != -1 && otherPlusIdx != -1) {
|
||||||
|
String thisSubtypeNoSuffix = this.subtype.substring(0, thisPlusIdx);
|
||||||
|
|
||||||
|
String thisSubtypeSuffix = this.subtype.substring(thisPlusIdx + 1);
|
||||||
|
String otherSubtypeSuffix = other.subtype.substring(otherPlusIdx + 1);
|
||||||
|
if (thisSubtypeSuffix.equals(otherSubtypeSuffix) && WILDCARD_TYPE.equals(thisSubtypeNoSuffix)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return isWildcardType();
|
return isWildcardType();
|
||||||
}
|
}
|
||||||
|
|
@ -192,9 +201,10 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
* audio/basic < audio/* < */* </blockquote>. That is, an explicit media type is sorted before an unspecific
|
* audio/basic < audio/* < */* </blockquote>. That is, an explicit media type is sorted before an unspecific
|
||||||
* media type. Quality parameters are also considered, so that <blockquote> audio/* < audio/*;q=0.7;
|
* media type. Quality parameters are also considered, so that <blockquote> audio/* < audio/*;q=0.7;
|
||||||
* audio/*;q=0.3</blockquote>.
|
* audio/*;q=0.3</blockquote>.
|
||||||
|
*
|
||||||
* @param other the media type to compare to
|
* @param other the media type to compare to
|
||||||
* @return a negative integer, zero, or a positive integer as this media type is less than, equal to,
|
* @return a negative integer, zero, or a positive integer as this media type is less than, equal to, or greater than
|
||||||
* or greater than the specified media type
|
* the specified media type
|
||||||
*/
|
*/
|
||||||
public int compareTo(MediaType other) {
|
public int compareTo(MediaType other) {
|
||||||
double qVal1 = this.getQualityValue();
|
double qVal1 = this.getQualityValue();
|
||||||
|
|
@ -263,7 +273,7 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
builder.append(this.type);
|
builder.append(this.type);
|
||||||
builder.append('/');
|
builder.append('/');
|
||||||
builder.append(this.subtype);
|
builder.append(this.subtype);
|
||||||
for (Map.Entry<String, String> entry :this. parameters.entrySet()) {
|
for (Map.Entry<String, String> entry : this.parameters.entrySet()) {
|
||||||
builder.append(';');
|
builder.append(';');
|
||||||
builder.append(entry.getKey());
|
builder.append(entry.getKey());
|
||||||
builder.append('=');
|
builder.append('=');
|
||||||
|
|
@ -271,9 +281,9 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given String into a single {@link MediaType}.
|
* Parse the given String into a single {@link MediaType}.
|
||||||
|
*
|
||||||
* @param mediaType the string to parse
|
* @param mediaType the string to parse
|
||||||
* @return the media type
|
* @return the media type
|
||||||
* @throws IllegalArgumentException if the string cannot be parsed
|
* @throws IllegalArgumentException if the string cannot be parsed
|
||||||
|
|
@ -309,8 +319,9 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse the given, comma-seperated string into a list of {@link MediaType} objects.
|
* Parse the given, comma-seperated string into a list of {@link MediaType} objects. <p>This method can be used to
|
||||||
* <p>This method can be used to parse an Accept or Content-Type header.
|
* parse an Accept or Content-Type header.
|
||||||
|
*
|
||||||
* @param mediaTypes the string to parse
|
* @param mediaTypes the string to parse
|
||||||
* @return the list of media types
|
* @return the list of media types
|
||||||
* @throws IllegalArgumentException if the string cannot be parsed
|
* @throws IllegalArgumentException if the string cannot be parsed
|
||||||
|
|
@ -328,8 +339,9 @@ public class MediaType implements Comparable<MediaType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a string representation of the given list of {@link MediaType} objects.
|
* Return a string representation of the given list of {@link MediaType} objects. <p>This method can be used to for an
|
||||||
* <p>This method can be used to for an Accept or Content-Type header.
|
* Accept or Content-Type header.
|
||||||
|
*
|
||||||
* @param mediaTypes the string to parse
|
* @param mediaTypes the string to parse
|
||||||
* @return the list of media types
|
* @return the list of media types
|
||||||
* @throws IllegalArgumentException if the String cannot be parsed
|
* @throws IllegalArgumentException if the String cannot be parsed
|
||||||
|
|
|
||||||
|
|
@ -16,28 +16,35 @@
|
||||||
|
|
||||||
package org.springframework.http;
|
package org.springframework.http;
|
||||||
|
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.nio.charset.Charset;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
/**
|
/** @author Arjen Poutsma */
|
||||||
* @author Arjen Poutsma
|
|
||||||
*/
|
|
||||||
public class MediaTypeTests {
|
public class MediaTypeTests {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void includes() throws Exception {
|
public void includes() throws Exception {
|
||||||
MediaType type1 = new MediaType("text", "plain");
|
MediaType textPlain = new MediaType("text", "plain");
|
||||||
MediaType type2 = new MediaType("text", "plain");
|
assertTrue("Equal types is not inclusive", textPlain.includes(textPlain));
|
||||||
assertTrue("Equal types is not inclusive", type1.includes(type2));
|
MediaType allText = new MediaType("text");
|
||||||
type1 = new MediaType("text");
|
assertTrue("All subtypes is not inclusive", allText.includes(textPlain));
|
||||||
assertTrue("All subtypes is not inclusive", type1.includes(type2));
|
assertFalse("All subtypes is not inclusive", textPlain.includes(allText));
|
||||||
type1 = MediaType.ALL;
|
assertTrue("All types is not inclusive", MediaType.ALL.includes(textPlain));
|
||||||
assertTrue("All types is not inclusive", type1.includes(type2));
|
assertFalse("All types is not inclusive", textPlain.includes(MediaType.ALL));
|
||||||
|
|
||||||
|
MediaType applicationSoapXml = new MediaType("application", "soap+xml");
|
||||||
|
MediaType applicationWildcardXml = new MediaType("application", "*+xml");
|
||||||
|
|
||||||
|
assertTrue(applicationSoapXml.includes(applicationSoapXml));
|
||||||
|
assertTrue(applicationWildcardXml.includes(applicationWildcardXml));
|
||||||
|
|
||||||
|
assertTrue(applicationWildcardXml.includes(applicationSoapXml));
|
||||||
|
assertFalse(applicationSoapXml.includes(applicationWildcardXml));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue