001/* 002 * Copyright 2002-2018 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.util.comparator; 018 019import java.io.Serializable; 020import java.util.ArrayList; 021import java.util.Comparator; 022import java.util.List; 023 024import org.springframework.lang.Nullable; 025import org.springframework.util.Assert; 026 027/** 028 * A comparator that chains a sequence of one or more Comparators. 029 * 030 * <p>A compound comparator calls each Comparator in sequence until a single 031 * Comparator returns a non-zero result, or the comparators are exhausted and 032 * zero is returned. 033 * 034 * <p>This facilitates in-memory sorting similar to multi-column sorting in SQL. 035 * The order of any single Comparator in the list can also be reversed. 036 * 037 * @author Keith Donald 038 * @author Juergen Hoeller 039 * @since 1.2.2 040 * @param <T> the type of objects that may be compared by this comparator 041 * @deprecated as of Spring Framework 5.0, in favor of the standard JDK 8 042 * {@link Comparator#thenComparing(Comparator)} 043 */ 044@Deprecated 045@SuppressWarnings({"serial", "rawtypes"}) 046public class CompoundComparator<T> implements Comparator<T>, Serializable { 047 048 private final List<InvertibleComparator> comparators; 049 050 051 /** 052 * Construct a CompoundComparator with initially no Comparators. Clients 053 * must add at least one Comparator before calling the compare method or an 054 * IllegalStateException is thrown. 055 */ 056 public CompoundComparator() { 057 this.comparators = new ArrayList<>(); 058 } 059 060 /** 061 * Construct a CompoundComparator from the Comparators in the provided array. 062 * <p>All Comparators will default to ascending sort order, 063 * unless they are InvertibleComparators. 064 * @param comparators the comparators to build into a compound comparator 065 * @see InvertibleComparator 066 */ 067 @SuppressWarnings("unchecked") 068 public CompoundComparator(Comparator... comparators) { 069 Assert.notNull(comparators, "Comparators must not be null"); 070 this.comparators = new ArrayList<>(comparators.length); 071 for (Comparator comparator : comparators) { 072 addComparator(comparator); 073 } 074 } 075 076 077 /** 078 * Add a Comparator to the end of the chain. 079 * <p>The Comparator will default to ascending sort order, 080 * unless it is a InvertibleComparator. 081 * @param comparator the Comparator to add to the end of the chain 082 * @see InvertibleComparator 083 */ 084 @SuppressWarnings("unchecked") 085 public void addComparator(Comparator<? extends T> comparator) { 086 if (comparator instanceof InvertibleComparator) { 087 this.comparators.add((InvertibleComparator) comparator); 088 } 089 else { 090 this.comparators.add(new InvertibleComparator(comparator)); 091 } 092 } 093 094 /** 095 * Add a Comparator to the end of the chain using the provided sort order. 096 * @param comparator the Comparator to add to the end of the chain 097 * @param ascending the sort order: ascending (true) or descending (false) 098 */ 099 @SuppressWarnings("unchecked") 100 public void addComparator(Comparator<? extends T> comparator, boolean ascending) { 101 this.comparators.add(new InvertibleComparator(comparator, ascending)); 102 } 103 104 /** 105 * Replace the Comparator at the given index. 106 * <p>The Comparator will default to ascending sort order, 107 * unless it is a InvertibleComparator. 108 * @param index the index of the Comparator to replace 109 * @param comparator the Comparator to place at the given index 110 * @see InvertibleComparator 111 */ 112 @SuppressWarnings("unchecked") 113 public void setComparator(int index, Comparator<? extends T> comparator) { 114 if (comparator instanceof InvertibleComparator) { 115 this.comparators.set(index, (InvertibleComparator) comparator); 116 } 117 else { 118 this.comparators.set(index, new InvertibleComparator(comparator)); 119 } 120 } 121 122 /** 123 * Replace the Comparator at the given index using the given sort order. 124 * @param index the index of the Comparator to replace 125 * @param comparator the Comparator to place at the given index 126 * @param ascending the sort order: ascending (true) or descending (false) 127 */ 128 public void setComparator(int index, Comparator<T> comparator, boolean ascending) { 129 this.comparators.set(index, new InvertibleComparator<>(comparator, ascending)); 130 } 131 132 /** 133 * Invert the sort order of each sort definition contained by this compound 134 * comparator. 135 */ 136 public void invertOrder() { 137 for (InvertibleComparator comparator : this.comparators) { 138 comparator.invertOrder(); 139 } 140 } 141 142 /** 143 * Invert the sort order of the sort definition at the specified index. 144 * @param index the index of the comparator to invert 145 */ 146 public void invertOrder(int index) { 147 this.comparators.get(index).invertOrder(); 148 } 149 150 /** 151 * Change the sort order at the given index to ascending. 152 * @param index the index of the comparator to change 153 */ 154 public void setAscendingOrder(int index) { 155 this.comparators.get(index).setAscending(true); 156 } 157 158 /** 159 * Change the sort order at the given index to descending sort. 160 * @param index the index of the comparator to change 161 */ 162 public void setDescendingOrder(int index) { 163 this.comparators.get(index).setAscending(false); 164 } 165 166 /** 167 * Returns the number of aggregated comparators. 168 */ 169 public int getComparatorCount() { 170 return this.comparators.size(); 171 } 172 173 174 @Override 175 @SuppressWarnings("unchecked") 176 public int compare(T o1, T o2) { 177 Assert.state(!this.comparators.isEmpty(), 178 "No sort definitions have been added to this CompoundComparator to compare"); 179 for (InvertibleComparator comparator : this.comparators) { 180 int result = comparator.compare(o1, o2); 181 if (result != 0) { 182 return result; 183 } 184 } 185 return 0; 186 } 187 188 189 @Override 190 @SuppressWarnings("unchecked") 191 public boolean equals(@Nullable Object other) { 192 return (this == other || (other instanceof CompoundComparator && 193 this.comparators.equals(((CompoundComparator<T>) other).comparators))); 194 } 195 196 @Override 197 public int hashCode() { 198 return this.comparators.hashCode(); 199 } 200 201 @Override 202 public String toString() { 203 return "CompoundComparator: " + this.comparators; 204 } 205 206}