Refactor MimeType/MediaType specificity
This commit makes several changes to MimeType and MediaType related to the topic of specificity. This commit deprecates the MimeType and MediaType Comparators. Comparators require a transitive relationship, and the desired order for these types is not transitive (see #27488). Instead, this commit introduces two new MimeType methods: isMoreSpecific and isLessSpecific, both of which return booleans. MediaType overrides these methods to include the quality factor (q) in the comparison. All MediaType sorting methods have been deprecated in favor of MimeTypeUtils::sortBySpecificity. This sorting method now uses MimeType::isLessSpecific in combination a bubble sort algorithm (which does not require a transitive compare function). Closes gh-27580
This commit is contained in:
committed by
Arjen Poutsma
parent
a7789db067
commit
6d9136013e
@@ -534,6 +534,82 @@ public class MediaType extends MimeType implements Serializable {
|
||||
return (qualityFactor != null ? Double.parseDouble(unquote(qualityFactor)) : 1D);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this {@code MediaType} more specific than the given type.
|
||||
* <ol>
|
||||
* <li>if this media type has a {@linkplain #getQualityValue() quality factor} higher than the other,
|
||||
* then this method returns {@code true}.</li>
|
||||
* <li>if this media type has a {@linkplain #getQualityValue() quality factor} lower than the other,
|
||||
* then this method returns {@code false}.</li>
|
||||
* <li>if this mime type has a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does not, then this method returns {@code false}.</li>
|
||||
* <li>if this mime type does not have a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does, then this method returns {@code true}.</li>
|
||||
* <li>if this mime type has a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does not, then this method returns {@code false}.</li>
|
||||
* <li>if this mime type does not have a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does, then this method returns {@code true}.</li>
|
||||
* <li>if the two mime types have identical {@linkplain #getType() type} and
|
||||
* {@linkplain #getSubtype() subtype}, then the mime type with the most
|
||||
* parameters is more specific than the other.</li>
|
||||
* <li>Otherwise, this method returns {@code false}.</li>
|
||||
* </ol>
|
||||
* @param other the {@code MimeType} to be compared
|
||||
* @return the result of the comparison
|
||||
* @since 6.0
|
||||
* @see #isLessSpecific(MimeType)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7231#section-5.3.2">HTTP 1.1: Semantics
|
||||
* and Content, section 5.3.2</a>
|
||||
*/
|
||||
@Override
|
||||
public boolean isMoreSpecific(MimeType other) {
|
||||
Assert.notNull(other, "Other must not be null");
|
||||
if (other instanceof MediaType otherMediaType) {
|
||||
double quality1 = getQualityValue();
|
||||
double quality2 = otherMediaType.getQualityValue();
|
||||
if (quality1 > quality2) {
|
||||
return true;
|
||||
}
|
||||
else if (quality1 < quality2) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return super.isMoreSpecific(other);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this {@code MediaType} more specific than the given type.
|
||||
* <ol>
|
||||
* <li>if this media type has a {@linkplain #getQualityValue() quality factor} higher than the other,
|
||||
* then this method returns {@code false}.</li>
|
||||
* <li>if this media type has a {@linkplain #getQualityValue() quality factor} lower than the other,
|
||||
* then this method returns {@code true}.</li>
|
||||
* <li>if this mime type has a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does not, then this method returns {@code true}.</li>
|
||||
* <li>if this mime type does not have a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does, then this method returns {@code false}.</li>
|
||||
* <li>if this mime type has a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does not, then this method returns {@code true}.</li>
|
||||
* <li>if this mime type does not have a {@linkplain #isWildcardType() wildcard type},
|
||||
* and the other does, then this method returns {@code false}.</li>
|
||||
* <li>if the two mime types have identical {@linkplain #getType() type} and
|
||||
* {@linkplain #getSubtype() subtype}, then the mime type with the least
|
||||
* parameters is less specific than the other.</li>
|
||||
* <li>Otherwise, this method returns {@code false}.</li>
|
||||
* </ol>
|
||||
* @param other the {@code MimeType} to be compared
|
||||
* @return the result of the comparison
|
||||
* @since 6.0
|
||||
* @see #isMoreSpecific(MimeType)
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7231#section-5.3.2">HTTP 1.1: Semantics
|
||||
* and Content, section 5.3.2</a>
|
||||
*/
|
||||
@Override
|
||||
public boolean isLessSpecific(MimeType other) {
|
||||
Assert.notNull(other, "Other must not be null");
|
||||
return other.isMoreSpecific(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicate whether this {@code MediaType} includes the given media type.
|
||||
* <p>For instance, {@code text/*} includes {@code text/plain} and {@code text/html},
|
||||
@@ -731,9 +807,9 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* <blockquote>audio/basic == text/html</blockquote>
|
||||
* <blockquote>audio/basic == audio/wave</blockquote>
|
||||
* @param mediaTypes the list of media types to be sorted
|
||||
* @see <a href="https://tools.ietf.org/html/rfc7231#section-5.3.2">HTTP 1.1: Semantics
|
||||
* and Content, section 5.3.2</a>
|
||||
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void sortBySpecificity(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
@@ -760,7 +836,9 @@ public class MediaType extends MimeType implements Serializable {
|
||||
* </ol>
|
||||
* @param mediaTypes the list of media types to be sorted
|
||||
* @see #getQualityValue()
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public static void sortByQualityValue(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
@@ -771,9 +849,9 @@ public class MediaType extends MimeType implements Serializable {
|
||||
/**
|
||||
* Sorts the given list of {@code MediaType} objects by specificity as the
|
||||
* primary criteria and quality value the secondary.
|
||||
* @see MediaType#sortBySpecificity(List)
|
||||
* @see MediaType#sortByQualityValue(List)
|
||||
* @deprecated As of 6.0, in favor of {@link MimeTypeUtils#sortBySpecificity(List)}
|
||||
*/
|
||||
@Deprecated
|
||||
public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) {
|
||||
Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
|
||||
if (mediaTypes.size() > 1) {
|
||||
@@ -784,7 +862,9 @@ public class MediaType extends MimeType implements Serializable {
|
||||
|
||||
/**
|
||||
* Comparator used by {@link #sortByQualityValue(List)}.
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Comparator<MediaType> QUALITY_VALUE_COMPARATOR = (mediaType1, mediaType2) -> {
|
||||
double quality1 = mediaType1.getQualityValue();
|
||||
double quality2 = mediaType2.getQualityValue();
|
||||
@@ -822,7 +902,9 @@ public class MediaType extends MimeType implements Serializable {
|
||||
|
||||
/**
|
||||
* Comparator used by {@link #sortBySpecificity(List)}.
|
||||
* @deprecated As of 6.0, with no direct replacement
|
||||
*/
|
||||
@Deprecated
|
||||
public static final Comparator<MediaType> SPECIFICITY_COMPARATOR = new SpecificityComparator<>() {
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user