SortUtil.java
package com.reallifedeveloper.tools.test.database.inmemory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import org.springframework.data.domain.Sort;
import org.springframework.data.domain.Sort.NullHandling;
import org.springframework.data.domain.Sort.Order;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import lombok.AllArgsConstructor;
import com.reallifedeveloper.tools.test.TestUtil;
/**
* A helper class to assist with sorting lists in accordance with {@code org.springframework.data.domain.Sort} instances.
*
* @author RealLifeDeveloper
*/
public final class SortUtil {
/**
* Since this is a utility class that should not be instantiated, we hide the only constructor.
*/
private SortUtil() {
}
/**
* Sorts the given list according to the sort definition provided.
*
* @param <T> the type of elements in the list
* @param items the list of items to sort
* @param sort the {@code org.springframework.data.domain.Sort} instance defining how the list should be sorted
*
* @return a copy of {@code items}, sorted according to {@code sort}
*/
public static <T> List<T> sort(List<T> items, Sort sort) {
List<T> sortedItems = new ArrayList<>(items);
// We reverse the Order instances so that we sort by the least important first and the most important last.
List<Order> orders = reverseOrders(sort);
for (Order order : orders) {
sort(sortedItems, order);
}
return sortedItems;
}
private static List<Order> reverseOrders(Sort sort) {
List<Order> orders = new ArrayList<>(sort.toList());
Collections.reverse(orders);
return orders;
}
private static <T> void sort(List<T> items, Order order) {
Collections.sort(items, new FieldComparator<>(order));
}
@AllArgsConstructor
@SuppressFBWarnings(value = "SE_COMPARATOR_SHOULD_BE_SERIALIZABLE", justification = "This class is only used interally when sorting")
private static final class FieldComparator<T> implements Comparator<T> {
private Order order;
@Override
@SuppressWarnings("unchecked")
public int compare(T o1, T o2) {
T fieldValue1 = (T) TestUtil.getFieldValue(o1, order.getProperty());
T fieldValue2 = (T) TestUtil.getFieldValue(o2, order.getProperty());
return nullSafeCompare(fieldValue1, fieldValue2);
}
@SuppressWarnings("unchecked")
private int nullSafeCompare(T fieldValue1, T fieldValue2) {
if (fieldValue1 == null) {
if (fieldValue2 == null) {
return 0;
} else if (order.getNullHandling() == NullHandling.NULLS_FIRST) {
return -1;
} else {
return 1;
}
}
if (fieldValue2 == null) {
if (order.getNullHandling() == NullHandling.NULLS_FIRST) {
return 1;
} else {
return -1;
}
}
// We simply try to cast the field value to Comparable, it it fails we get a ClassCastException:
int compareResult = ((Comparable<T>) fieldValue1).compareTo(fieldValue2);
if (order.isAscending()) {
return compareResult;
} else {
return invert(compareResult);
}
}
private static int invert(int c) {
if (c < 0) {
return 1;
} else if (c > 0) {
return -1;
} else {
return 0;
}
}
}
}