All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jett.util.OrderByComparator Maven / Gradle / Ivy

package net.sf.jett.util;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;

import net.sf.jagg.exception.JaggException;
import net.sf.jagg.util.MethodCache;
import net.sf.jett.exception.ParseException;

/**
 * 

An OrderByComparator is a Comparator that is * capable of comparing two objects based on a dynamic list of properties of * the objects of type T. It can sort any of its properties * ascending or descending, and for any of its properties, it can place nulls * first or last. Like SQL, this will default to ascending. Nulls default to * last if ascending, and first if descending.

*

This is based on jAgg's PropertiesComparator, which as of * the time of creation of this class always does ascending, nulls last.

* * @author Randy Gettman * @since 0.3.0 */ public class OrderByComparator implements Comparator { /** * Sort ascending (default). */ public static final String ASC = "ASC"; /** * Sort descending. */ public static final String DESC = "DESC"; /** * Use this to indicate which sequence nulls should be ordered. */ public static final String NULLS = "NULLS"; /** * Sort nulls first (default if descending order). */ public static final String FIRST = "FIRST"; /** * Sort nulls last (default if ascending order). */ public static final String LAST = "LAST"; /** * Constant to order ascending. */ public static final int ORDER_ASC = 1; /** * Constant to order descending. */ public static final int ORDER_DESC = -1; /** * Constant to order nulls last. */ public static final int NULLS_LAST = 1; /** * Constant to order nulls first. */ public static final int NULLS_FIRST = -1; private List myProperties; private List myOrderings; private List myNullOrderings; private int mySize; /** * Constructs an OrderByComparator based on a List * of expressions, of the format "property [ASC|DESC] [NULLS FIRST|LAST]". * @param expressions A List of expressions. * @throws ParseException If there is a problem parsing the expressions. */ public OrderByComparator(List expressions) { setExpressions(expressions); } /** * Sets the internal lists for all properties, order sequences, and null * order sequences. * @param expressions A List of expressions. * @throws ParseException If there is a problem parsing the expressions. */ private void setExpressions(List expressions) { if (expressions == null || expressions.size() <= 0) throw new ParseException("No order by expressions found."); mySize = expressions.size(); myProperties = new ArrayList(mySize); myOrderings = new ArrayList(mySize); myNullOrderings = new ArrayList(mySize); for (String expr : expressions) { String[] parts = expr.split("\\s+"); String property; int ordering; int nullOrdering; if (parts.length > 0 && parts.length < 5) { property = parts[0]; ordering = ORDER_ASC; nullOrdering = NULLS_LAST; if (parts.length == 2 || parts.length == 4) { // ordering is next. if (ASC.equalsIgnoreCase(parts[1])) { ordering = ORDER_ASC; nullOrdering = NULLS_LAST; } else if (DESC.equalsIgnoreCase(parts[1])) { ordering = ORDER_DESC; nullOrdering = NULLS_FIRST; } else throw new ParseException("Expected \"" + ASC + "\" or \"" + DESC + ": " + expr); } if (parts.length == 3 || parts.length == 4) { if (!NULLS.equalsIgnoreCase(parts[parts.length - 2])) throw new ParseException("Expected \"" + NULLS + " " + FIRST + "|" + LAST + ": " + expr); if (LAST.equalsIgnoreCase(parts[parts.length - 1])) nullOrdering = NULLS_LAST; else if (FIRST.equalsIgnoreCase(parts[parts.length - 1])) nullOrdering = NULLS_FIRST; else throw new ParseException("Expected \"" + FIRST + "\" or \"" + LAST + ": " + expr); } } else { throw new ParseException("Expected \"property\" [" + ASC + "|" + DESC + "] [" + NULLS + " ]" + FIRST + "|" + LAST + ": " + expr); } myProperties.add(property); myOrderings.add(ordering); myNullOrderings.add(nullOrdering); } } /** *

Compares the given objects to determine order. Fulfills the * Comparator contract by returning a negative integer, 0, or a * positive integer if o1 is less than, equal to, or greater * than o2.

*

This compare method respects all properties, their order sequences, * and their null order sequences.

* * @param o1 The left-hand-side object to compare. * @param o2 The right-hand-side object to compare. * @return A negative integer, 0, or a positive integer if o1 * is less than, equal to, or greater than o2. * @throws UnsupportedOperationException If any property specified in the * constructor doesn't correspond to a no-argument "get<Property>" * getter method in T, or if the property's type is not * Comparable. */ @SuppressWarnings("unchecked") public int compare(T o1, T o2) throws UnsupportedOperationException { int comp; for (int i = 0; i < mySize; i++) { String property = myProperties.get(i); int ordering = myOrderings.get(i); int nullOrdering = myNullOrderings.get(i); Comparable value1, value2; // This had to be copied from Aggregator.java, because Aggregator's // static method "getValueFromProperty" is protected. // Otherwise, we could call "Aggregator.getValueFromProperty", which // wraps all of the checked exceptions in an // UnsupportedOperationException. MethodCache cache = MethodCache.getMethodCache(); try { value1 = (Comparable) cache.getValueFromProperty(o1, property); value2 = (Comparable) cache.getValueFromProperty(o2, property); } catch (JaggException e) { throw new UnsupportedOperationException("No matching method found for \"" + property + "\".", e); } try { if (value1 == null) { if (value2 == null) comp = 0; else comp = nullOrdering; } else { if (value2 == null) comp = -nullOrdering; else comp = ordering * value1.compareTo(value2); } if (comp != 0) return comp; } catch (ClassCastException e) { throw new UnsupportedOperationException("Property \"" + property + "\" needs to be Comparable."); } } return 0; } /** * Indicates whether the given OrderByComparator is equal to * this OrderByComparator. All property names must match in * order, and all of the order sequences and null order sequences must * match. * * @param obj The other OrderByComparator. */ public boolean equals(Object obj) { if (obj instanceof OrderByComparator) { OrderByComparator otherComp = (OrderByComparator) obj; if (mySize != otherComp.mySize) return false; for (int i = 0; i < mySize; i++) { if (!myProperties.get(i).equals(otherComp.myProperties.get(i))) return false; if (myOrderings.get(i) != otherComp.myOrderings.get(i)) return false; if (myNullOrderings.get(i) != otherComp.myNullOrderings.get(i)) return false; } return true; } return false; } /** * Returns a List of all properties. * @return A List of all properties. */ public List getProperties() { return myProperties; } /** * Returns a List of orderings. * @return A List of orderings. * @see #ORDER_ASC * @see #ORDER_DESC */ public List getOrderings() { return myOrderings; } /** * Returns a List of null orderings. * @return A List of null orderings. * @see #NULLS_FIRST * @see #NULLS_LAST */ public List getNullOrderings() { return myNullOrderings; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy