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

com.findwise.tools.Comparator Maven / Gradle / Ivy

There is a newer version: 0.5.0
Show newest version
package com.findwise.tools;

import java.lang.reflect.Method;
import java.math.BigDecimal;


/**
 * Utility class for comparing any two objects for equality.
 * 
 * @author joel.westberg
 */
public final class Comparator {
	private Comparator() {}
	
	/**
	 * Nullsafe method for checking equality of the values of two Number objects 
	 */
	public static boolean equals(Number o, Number p) {
		if(o==null && p==null) {
			return true;
		}
		if(o==null ^ p == null) {
			return false;
		}
		
		if(o.equals(p)) {
			return true;
		}
		
		return comparisonEquals(o, p);
	}
	
	/**
	 * Not nullsafe. Converts to double or long value, comparing these.
	 */
	private static boolean comparisonEquals(Number o, Number p) {
		if(isDecimal(o)) {
			if(isDecimal(p)) {
				return o.doubleValue() == p.doubleValue();
			}
			else {
				return o.doubleValue() == p.longValue();
			}
		} else {
			if(isDecimal(p)) {
				return o.longValue() == p.doubleValue();
			}
			else {
				return o.longValue() == p.longValue();
			}
		}
	}
	
	/**
	 * @return true if o is an instance of Double, Float or BigDecimal
	 */
	public static boolean isDecimal(Number o) {
		return o instanceof Double || o instanceof Float || o instanceof BigDecimal;
	}
	
	/**
	 * @return true if o is an instance of Byte, Integer, Long, Short, BigInteger, AtomicLong or AtomicInteger.
	 */
	public static boolean isInteger(Number o) {
		return !isDecimal(o);
	}
	
	/**
	 * True if o is Character or is a 1-length char array, or CharSequence.
	 */
	public static boolean isCharacter(Object o) {
		try {
			toCharacter(o);
		}
		catch(ClassCastException e) {
			return false;
		}
		
		return true;
	}
	
	/**
	 * Throws ClassCastException if the passed object cannot be converted to a
	 * Char. isCharacter() method can confirm if this is the case or not.
	 */
	public static Character toCharacter(Object o) {
		if (o instanceof Character) {
			return (Character) o;
		}

		if (o instanceof CharSequence && ((CharSequence) o).length() == 1) {
			return ((CharSequence) o).charAt(0);
		}

		if (o instanceof char[] && ((char[]) o).length == 1) {
			return ((char[]) o)[0];
		}

		if (o instanceof Character[] && ((Character[]) o).length == 1) {
			return ((Character[]) o)[0];
		}

		throw new ClassCastException("Cannot cast " + o.getClass().getName() + " to " + Character.class);
	}
	
	/**
	 * Nullsafe method for checking equality of the values of any two objects
	 */
	@SuppressWarnings({ "unchecked", "rawtypes" })
	public static boolean equals(Object o, Object p) {
		
		if(o==null && p == null) {
			return true;
		}
		else if(o == null || p == null) {
			return false;
		}
		else if(o.equals(p)) {
			return true;
		}
		
		Object o2 = o;
		Object p2 = p;
		
		if(isCharacter(o)) {
			o2 = (int)(char)toCharacter(o);
		}
		if(isCharacter(p)) {
			p2 = (int)(char)toCharacter(p);
		}
		
		try {
			return equals((Number) o2, (Number) p2);
		}
		catch(Exception e) {
			//Not Numbers
		}
		
		try {
			return ((Comparable) o2).compareTo(p2)==0;
		} catch(Exception e) {
			// Not comparable
		}
		
		return false;
	}
	
	/**
	 * This method will take a Class object and perform duck-typing on the other two
	 * supplied objects. If object o and o2 all have the getters of class C, these will be called and compared for equality.
	 * 
	 * @param c
	 * @param o
	 * @param o2
	 * @return
	 */
	@SuppressWarnings("rawtypes")
	public static boolean getterEqual(Class c, Object o, Object o2) {
		Method[] methods = c.getMethods();
		for(Method m : methods) {
			if(isGetter(m)) {
				try {
					Object oRes = m.invoke(o);
					Object o2Res = m.invoke(o2);
					if(!oRes.equals(o2Res)) {
						return false;
					}
				}
				catch(Exception e) {
					return false;
				}
			}
		}
		
		return true;
	}
	
	private static boolean isGetter(Method m) {
		String name = m.getName();
		if(m.getParameterTypes().length!=0) {
			return false;
		}
		
		if(name.startsWith("get") && name.length()>3 && Character.isUpperCase(name.charAt(3))) {
			return true;
		}
		
		if(m.getReturnType().equals(Boolean.class) && name.startsWith("is") && name.length()>2 && Character.isUpperCase(name.charAt(2))) {
			return true;
		}
		
		return false;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy