01: /*
02: *
03: * Copyright (c) 2003 Adrian Price. All rights reserved.
04: */
05:
06: package org.obe.engine.util;
07:
08: import org.obe.OBERuntimeException;
09: import org.obe.util.ClassUtils;
10:
11: import java.beans.PropertyDescriptor;
12: import java.lang.reflect.InvocationTargetException;
13: import java.lang.reflect.Method;
14: import java.util.Comparator;
15:
16: /**
17: * Performs multi-level property-based comparisons between objects of a
18: * specified class. The named properties must either be of a primitive type, or
19: * of a class that implements the <code>java.lang.Comparable</code> interface.
20: * The class is threadsafe, so it is not necessary to pool or repeatedly
21: * allocate instances.
22: *
23: * @author Adrian Price.
24: */
25: public class PropertyComparator implements Comparator {
26: private Method[] _getters;
27:
28: public PropertyComparator(Class beanClass, Class stopClass,
29: String propName) {
30:
31: this (beanClass, stopClass, new String[] { propName });
32: }
33:
34: public PropertyComparator(Class beanClass, Class stopClass,
35: String[] propNames) {
36:
37: // Introspect the bean's properties.
38: PropertyDescriptor[] propDescs = ClassUtils.introspect(
39: beanClass, stopClass);
40:
41: // Find the getter method for each of the requested properties.
42: int len = propNames.length;
43: _getters = new Method[len];
44: for (int i = 0; i < len; i++) {
45: // Find the read method for the property.
46: Method getter = null;
47: for (int j = 0; j < propDescs.length; j++) {
48: PropertyDescriptor propDesc = propDescs[j];
49: if (propDesc.getName().equals(propNames[i])) {
50: getter = _getters[i] = propDesc.getReadMethod();
51: break;
52: }
53: }
54: if (getter == null)
55: throw new IllegalArgumentException(propNames[i]);
56: }
57: }
58:
59: public int compare(Object o1, Object o2) {
60: return compare(o1, o2, -1);
61: }
62:
63: /**
64: * Compares the properties at the specified index.
65: *
66: * @param o1
67: * @param o2
68: * @param index Index into the <code>propNames</code> array passed to the
69: * constructor. <code>-1</code> means compare all properties.
70: * @return The result of the comparison.
71: */
72: public int compare(Object o1, Object o2, int index) {
73: int diff = 0;
74: try {
75: // Compare property values until either we've checked them all, or
76: // we encounter one that is not equal in both objects.
77: for (int i = index == -1 ? 0 : index, n = index == -1 ? _getters.length
78: : index + 1; i < n && diff == 0; i++) {
79:
80: Method method = _getters[i];
81: // Casts required to suppress JDK1.5 varargs compiler warning.
82: diff = compareProperties(method.invoke(o1,
83: (Object[]) null), method.invoke(o2,
84: (Object[]) null));
85: }
86: } catch (IllegalAccessException e) {
87: throw new OBERuntimeException(e);
88: } catch (InvocationTargetException e) {
89: throw new OBERuntimeException(e);
90: }
91: return diff;
92: }
93:
94: protected int compareProperties(Object o1, Object o2) {
95: return Comparators.compare(o1, o2);
96: }
97: }
|