Comparators entry point with generically typed factory methods

Issue: SPR-14779
This commit is contained in:
Juergen Hoeller 2017-02-15 18:05:32 +01:00
parent 07dd61eabd
commit 5f531a7a7d
10 changed files with 133 additions and 46 deletions

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 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.
@ -52,7 +52,6 @@ import org.springframework.core.convert.converter.Converter;
import org.springframework.core.convert.converter.ConvertingComparator; import org.springframework.core.convert.converter.ConvertingComparator;
import org.springframework.util.ReflectionUtils; import org.springframework.util.ReflectionUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.comparator.CompoundComparator;
import org.springframework.util.comparator.InstanceComparator; import org.springframework.util.comparator.InstanceComparator;
/** /**
@ -73,8 +72,7 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
private static final Comparator<Method> METHOD_COMPARATOR; private static final Comparator<Method> METHOD_COMPARATOR;
static { static {
CompoundComparator<Method> comparator = new CompoundComparator<>(); Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
comparator.addComparator(new ConvertingComparator<>(
new InstanceComparator<>( new InstanceComparator<>(
Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class), Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
new Converter<Method, Annotation>() { new Converter<Method, Annotation>() {
@ -84,15 +82,15 @@ public class ReflectiveAspectJAdvisorFactory extends AbstractAspectJAdvisorFacto
AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method); AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
return (annotation != null ? annotation.getAnnotation() : null); return (annotation != null ? annotation.getAnnotation() : null);
} }
})); });
comparator.addComparator(new ConvertingComparator<>( Comparator<Method> methodNameComparator = new ConvertingComparator<>(
new Converter<Method, String>() { new Converter<Method, String>() {
@Override @Override
public String convert(Method method) { public String convert(Method method) {
return method.getName(); return method.getName();
} }
})); });
METHOD_COMPARATOR = comparator; METHOD_COMPARATOR = adviceKindComparator.thenComparing(methodNameComparator);
} }

View File

@ -21,12 +21,12 @@ import java.util.Map;
import org.springframework.core.convert.ConversionService; import org.springframework.core.convert.ConversionService;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import org.springframework.util.comparator.ComparableComparator; import org.springframework.util.comparator.Comparators;
/** /**
* A {@link Comparator} that converts values before they are compared. The specified * A {@link Comparator} that converts values before they are compared.
* {@link Converter} will be used to convert each value before it passed to the underlying * The specified {@link Converter} will be used to convert each value
* {@code Comparator}. * before it passed to the underlying {@code Comparator}.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 3.2 * @since 3.2
@ -44,9 +44,8 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
* Create a new {@link ConvertingComparator} instance. * Create a new {@link ConvertingComparator} instance.
* @param converter the converter * @param converter the converter
*/ */
@SuppressWarnings("unchecked")
public ConvertingComparator(Converter<S, T> converter) { public ConvertingComparator(Converter<S, T> converter) {
this(ComparableComparator.INSTANCE, converter); this(Comparators.comparable(), converter);
} }
/** /**
@ -62,7 +61,7 @@ public class ConvertingComparator<S, T> implements Comparator<S> {
} }
/** /**
* Create a new {@link ComparableComparator} instance. * Create a new {@code ConvertingComparator} instance.
* @param comparator the underlying comparator * @param comparator the underlying comparator
* @param conversionService the conversion service * @param conversionService the conversion service
* @param targetType the target type * @param targetType the target type

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2017 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,23 +20,24 @@ import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
/** /**
* A Comparator for Boolean objects that can sort either true or false first. * A {@link Comparator} for {@link Boolean} objects that can sort either
* {@code true} or {@code false} first.
* *
* @author Keith Donald * @author Keith Donald
* @since 1.2.2 * @since 1.2.2
*/ */
@SuppressWarnings("serial") @SuppressWarnings("serial")
public final class BooleanComparator implements Comparator<Boolean>, Serializable { public class BooleanComparator implements Comparator<Boolean>, Serializable {
/** /**
* A shared default instance of this comparator, treating true lower * A shared default instance of this comparator,
* than false. * treating {@code true} lower than {@code false}.
*/ */
public static final BooleanComparator TRUE_LOW = new BooleanComparator(true); public static final BooleanComparator TRUE_LOW = new BooleanComparator(true);
/** /**
* A shared default instance of this comparator, treating true higher * A shared default instance of this comparator,
* than false. * treating {@code true} higher than {@code false}.
*/ */
public static final BooleanComparator TRUE_HIGH = new BooleanComparator(false); public static final BooleanComparator TRUE_HIGH = new BooleanComparator(false);
@ -64,20 +65,16 @@ public final class BooleanComparator implements Comparator<Boolean>, Serializabl
return (v1 ^ v2) ? ((v1 ^ this.trueLow) ? 1 : -1) : 0; return (v1 ^ v2) ? ((v1 ^ this.trueLow) ? 1 : -1) : 0;
} }
@Override @Override
public boolean equals(Object obj) { public boolean equals(Object obj) {
if (this == obj) { return (this == obj ||
return true; (obj instanceof BooleanComparator && (this.trueLow == ((BooleanComparator) obj).trueLow)));
}
if (!(obj instanceof BooleanComparator)) {
return false;
}
return (this.trueLow == ((BooleanComparator) obj).trueLow);
} }
@Override @Override
public int hashCode() { public int hashCode() {
return (this.trueLow ? -1 : 1) * getClass().hashCode(); return getClass().hashCode() * (this.trueLow ? -1 : 1);
} }
@Override @Override

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2017 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.
@ -29,9 +29,14 @@ import java.util.Comparator;
*/ */
public class ComparableComparator<T extends Comparable<T>> implements Comparator<T> { public class ComparableComparator<T extends Comparable<T>> implements Comparator<T> {
/**
* A shared instance of this default comparator
* @see Comparators#comparable()
*/
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static final ComparableComparator INSTANCE = new ComparableComparator(); public static final ComparableComparator INSTANCE = new ComparableComparator();
@Override @Override
public int compare(T o1, T o2) { public int compare(T o1, T o2) {
return o1.compareTo(o2); return o1.compareTo(o2);

View File

@ -0,0 +1,77 @@
/*
* Copyright 2002-2017 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.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.util.comparator;
import java.util.Comparator;
/**
* Convenient entry point with generically typed factory methods
* for common Spring {@link Comparator} variants.
*
* @author Juergen Hoeller
* @since 5.0
*/
public abstract class Comparators {
/**
* Return a {@link Comparable} adapter.
* @see ComparableComparator#INSTANCE
*/
@SuppressWarnings("unchecked")
public static <T> Comparator<T> comparable() {
return ComparableComparator.INSTANCE;
}
/**
* Return a {@link Comparable} adapter which accepts
* null values and sorts them lower than non-null values.
* @see NullSafeComparator#NULLS_LOW
*/
@SuppressWarnings("unchecked")
public static <T> Comparator<T> nullsLow() {
return NullSafeComparator.NULLS_LOW;
}
/**
* Return a decorator for the given comparator which accepts
* null values and sorts them lower than non-null values.
* @see NullSafeComparator#NullSafeComparator(boolean)
*/
public static <T> Comparator<T> nullsLow(Comparator<T> comparator) {
return new NullSafeComparator<T>(comparator, false);
}
/**
* Return a {@link Comparable} adapter which accepts
* null values and sorts them higher than non-null values.
* @see NullSafeComparator#NULLS_HIGH
*/
@SuppressWarnings("unchecked")
public static <T> Comparator<T> nullsHigh() {
return NullSafeComparator.NULLS_HIGH;
}
/**
* Return a decorator for the given comparator which accepts
* null values and sorts them higher than non-null values.
* @see NullSafeComparator#NullSafeComparator(boolean)
*/
public static <T> Comparator<T> nullsHigh(Comparator<T> comparator) {
return new NullSafeComparator<T>(comparator, false);
}
}

View File

@ -36,7 +36,10 @@ import org.springframework.util.Assert;
* @author Keith Donald * @author Keith Donald
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 1.2.2 * @since 1.2.2
* @deprecated as of Spring Framework 5.0, in favor of the standard JDK 8
* {@link Comparator#thenComparing(Comparator)}
*/ */
@Deprecated
@SuppressWarnings({"serial", "rawtypes"}) @SuppressWarnings({"serial", "rawtypes"})
public class CompoundComparator<T> implements Comparator<T>, Serializable { public class CompoundComparator<T> implements Comparator<T>, Serializable {
@ -165,10 +168,11 @@ public class CompoundComparator<T> implements Comparator<T>, Serializable {
return this.comparators.size(); return this.comparators.size();
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public int compare(T o1, T o2) { public int compare(T o1, T o2) {
Assert.state(this.comparators.size() > 0, Assert.state(!this.comparators.isEmpty(),
"No sort definitions have been added to this CompoundComparator to compare"); "No sort definitions have been added to this CompoundComparator to compare");
for (InvertibleComparator comparator : this.comparators) { for (InvertibleComparator comparator : this.comparators) {
int result = comparator.compare(o1, o2); int result = comparator.compare(o1, o2);
@ -179,6 +183,7 @@ public class CompoundComparator<T> implements Comparator<T>, Serializable {
return 0; return 0;
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean equals(Object obj) { public boolean equals(Object obj) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2015 the original author or authors. * Copyright 2002-2017 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.
@ -27,12 +27,12 @@ import org.springframework.util.Assert;
* *
* <p>Only the specified {@code instanceOrder} classes are considered during comparison. * <p>Only the specified {@code instanceOrder} classes are considered during comparison.
* If two objects are both instances of the ordered type this comparator will return a * If two objects are both instances of the ordered type this comparator will return a
* {@code 0}. Consider combining with a {@link CompoundComparator} if additional sorting * {@code 0}. Consider combining with {@link Comparator#thenComparing(Comparator)}
* is required. * if additional sorting is required.
* *
* @author Phillip Webb * @author Phillip Webb
* @since 3.2 * @since 3.2
* @see CompoundComparator * @see Comparator#thenComparing(Comparator)
* @param <T> the type of objects being compared * @param <T> the type of objects being compared
*/ */
public class InstanceComparator<T> implements Comparator<T> { public class InstanceComparator<T> implements Comparator<T> {
@ -46,7 +46,7 @@ public class InstanceComparator<T> implements Comparator<T> {
* objects. Classes earlier in the list will be given a higher priority. * objects. Classes earlier in the list will be given a higher priority.
*/ */
public InstanceComparator(Class<?>... instanceOrder) { public InstanceComparator(Class<?>... instanceOrder) {
Assert.notNull(instanceOrder, "'instanceOrder' must not be null"); Assert.notNull(instanceOrder, "'instanceOrder' array must not be null");
this.instanceOrder = instanceOrder; this.instanceOrder = instanceOrder;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2012 the original author or authors. * Copyright 2002-2017 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.
@ -29,7 +29,10 @@ import org.springframework.util.Assert;
* @author Keith Donald * @author Keith Donald
* @author Juergen Hoeller * @author Juergen Hoeller
* @since 1.2.2 * @since 1.2.2
* @deprecated as of Spring Framework 5.0, in favor of the standard JDK 8
* {@link Comparator#reversed()}
*/ */
@Deprecated
@SuppressWarnings("serial") @SuppressWarnings("serial")
public class InvertibleComparator<T> implements Comparator<T>, Serializable { public class InvertibleComparator<T> implements Comparator<T>, Serializable {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2016 the original author or authors. * Copyright 2002-2017 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.
@ -34,6 +34,7 @@ public class NullSafeComparator<T> implements Comparator<T> {
/** /**
* A shared default instance of this comparator, treating nulls lower * A shared default instance of this comparator, treating nulls lower
* than non-null objects. * than non-null objects.
* @see Comparators#nullsLow()
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static final NullSafeComparator NULLS_LOW = new NullSafeComparator<>(true); public static final NullSafeComparator NULLS_LOW = new NullSafeComparator<>(true);
@ -41,10 +42,12 @@ public class NullSafeComparator<T> implements Comparator<T> {
/** /**
* A shared default instance of this comparator, treating nulls higher * A shared default instance of this comparator, treating nulls higher
* than non-null objects. * than non-null objects.
* @see Comparators#nullsHigh()
*/ */
@SuppressWarnings("rawtypes") @SuppressWarnings("rawtypes")
public static final NullSafeComparator NULLS_HIGH = new NullSafeComparator<>(false); public static final NullSafeComparator NULLS_HIGH = new NullSafeComparator<>(false);
private final Comparator<T> nonNullComparator; private final Comparator<T> nonNullComparator;
private final boolean nullsLow; private final boolean nullsLow;
@ -64,9 +67,9 @@ public class NullSafeComparator<T> implements Comparator<T> {
* @see #NULLS_LOW * @see #NULLS_LOW
* @see #NULLS_HIGH * @see #NULLS_HIGH
*/ */
@SuppressWarnings({ "unchecked", "rawtypes"}) @SuppressWarnings("unchecked")
private NullSafeComparator(boolean nullsLow) { private NullSafeComparator(boolean nullsLow) {
this.nonNullComparator = new ComparableComparator(); this.nonNullComparator = ComparableComparator.INSTANCE;
this.nullsLow = nullsLow; this.nullsLow = nullsLow;
} }
@ -80,7 +83,7 @@ public class NullSafeComparator<T> implements Comparator<T> {
* @param nullsLow whether to treat nulls lower or higher than non-null objects * @param nullsLow whether to treat nulls lower or higher than non-null objects
*/ */
public NullSafeComparator(Comparator<T> comparator, boolean nullsLow) { public NullSafeComparator(Comparator<T> comparator, boolean nullsLow) {
Assert.notNull(comparator, "The non-null comparator is required"); Assert.notNull(comparator, "Non-null Comparator is required");
this.nonNullComparator = comparator; this.nonNullComparator = comparator;
this.nullsLow = nullsLow; this.nullsLow = nullsLow;
} }
@ -100,6 +103,7 @@ public class NullSafeComparator<T> implements Comparator<T> {
return this.nonNullComparator.compare(o1, o2); return this.nonNullComparator.compare(o1, o2);
} }
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public boolean equals(Object obj) { public boolean equals(Object obj) {
@ -115,7 +119,7 @@ public class NullSafeComparator<T> implements Comparator<T> {
@Override @Override
public int hashCode() { public int hashCode() {
return (this.nullsLow ? -1 : 1) * this.nonNullComparator.hashCode(); return this.nonNullComparator.hashCode() * (this.nullsLow ? -1 : 1);
} }
@Override @Override

View File

@ -33,7 +33,6 @@ import org.springframework.util.InvalidMimeTypeException;
import org.springframework.util.MimeType; import org.springframework.util.MimeType;
import org.springframework.util.MimeTypeUtils; import org.springframework.util.MimeTypeUtils;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.util.comparator.CompoundComparator;
/** /**
* A sub-class of {@link MimeType} that adds support for quality parameters as defined * A sub-class of {@link MimeType} that adds support for quality parameters as defined
@ -644,8 +643,8 @@ public class MediaType extends MimeType implements Serializable {
public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) { public static void sortBySpecificityAndQuality(List<MediaType> mediaTypes) {
Assert.notNull(mediaTypes, "'mediaTypes' must not be null"); Assert.notNull(mediaTypes, "'mediaTypes' must not be null");
if (mediaTypes.size() > 1) { if (mediaTypes.size() > 1) {
Collections.sort(mediaTypes, new CompoundComparator<>( Collections.sort(mediaTypes,
MediaType.SPECIFICITY_COMPARATOR, MediaType.QUALITY_VALUE_COMPARATOR)); MediaType.SPECIFICITY_COMPARATOR.thenComparing(MediaType.QUALITY_VALUE_COMPARATOR));
} }
} }