1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.commons.beanutils;
19
20 import java.lang.reflect.InvocationTargetException;
21 import java.io.Serializable;
22 import java.util.Comparator;
23 import org.apache.commons.collections.comparators.ComparableComparator;
24
25 /***
26 * <p>
27 * This comparator compares two beans by the specified bean property.
28 * It is also possible to compare beans based on nested, indexed,
29 * combined, mapped bean properties. Please see the {@link PropertyUtilsBean}
30 * documentation for all property name possibilities.
31 *
32 * </p><p>
33 * <strong>Note:</strong> The BeanComparator passes the values of the specified
34 * bean property to a ComparableComparator, if no comparator is
35 * specified in the constructor. If you are comparing two beans based
36 * on a property that could contain "null" values, a suitable <code>Comparator</code>
37 * or <code>ComparatorChain</code> should be supplied in the constructor.
38 * </p>
39 *
40 * @author <a href"mailto:epugh@upstate.com">Eric Pugh</a>
41 * @author Tim O'Brien
42 */
43 public class BeanComparator implements Comparator, Serializable {
44
45 private String property;
46 private Comparator comparator;
47
48 /***
49 * <p>Constructs a Bean Comparator without a property set.
50 * </p><p>
51 * <strong>Note</strong> that this is intended to be used
52 * only in bean-centric environments.
53 * </p><p>
54 * Until {@link #setProperty} is called with a non-null value.
55 * this comparator will compare the Objects only.
56 * </p>
57 */
58 public BeanComparator() {
59 this( null );
60 }
61
62 /***
63 * <p>Constructs a property-based comparator for beans.
64 * This compares two beans by the property
65 * specified in the property parameter. This constructor creates
66 * a <code>BeanComparator</code> that uses a <code>ComparableComparator</code>
67 * to compare the property values.
68 * </p>
69 *
70 * <p>Passing "null" to this constructor will cause the BeanComparator
71 * to compare objects based on natural order, that is
72 * <code>java.lang.Comparable</code>.
73 * </p>
74 *
75 * @param property String Name of a bean property, which may contain the
76 * name of a simple, nested, indexed, mapped, or combined
77 * property. See {@link PropertyUtilsBean} for property query language syntax.
78 * If the property passed in is null then the actual objects will be compared
79 */
80 public BeanComparator( String property ) {
81 this( property, ComparableComparator.getInstance() );
82 }
83
84 /***
85 * Constructs a property-based comparator for beans.
86 * This constructor creates
87 * a BeanComparator that uses the supplied Comparator to compare
88 * the property values.
89 *
90 * @param property Name of a bean property, can contain the name
91 * of a simple, nested, indexed, mapped, or combined
92 * property. See {@link PropertyUtilsBean} for property query language
93 * syntax.
94 * @param comparator BeanComparator will pass the values of the
95 * specified bean property to this Comparator.
96 * If your bean property is not a comparable or
97 * contains null values, a suitable comparator
98 * may be supplied in this constructor.
99 */
100 public BeanComparator( String property, Comparator comparator ) {
101 setProperty( property );
102 if (comparator != null) {
103 this.comparator = comparator;
104 } else {
105 this.comparator = ComparableComparator.getInstance();
106 }
107 }
108
109 /***
110 * Sets the method to be called to compare two JavaBeans
111 *
112 * @param property String method name to call to compare
113 * If the property passed in is null then the actual objects will be compared
114 */
115 public void setProperty( String property ) {
116 this.property = property;
117 }
118
119
120 /***
121 * Gets the property attribute of the BeanComparator
122 *
123 * @return String method name to call to compare.
124 * A null value indicates that the actual objects will be compared
125 */
126 public String getProperty() {
127 return property;
128 }
129
130
131 /***
132 * Gets the Comparator being used to compare beans.
133 *
134 * @return the Comparator being used to compare beans
135 */
136 public Comparator getComparator() {
137 return comparator;
138 }
139
140
141 /***
142 * Compare two JavaBeans by their shared property.
143 * If {@link #getProperty} is null then the actual objects will be compared.
144 *
145 * @param o1 Object The first bean to get data from to compare against
146 * @param o2 Object The second bean to get data from to compare
147 * @return int negative or positive based on order
148 */
149 public int compare( Object o1, Object o2 ) {
150
151 if ( property == null ) {
152
153 return comparator.compare( o1, o2 );
154 }
155
156 try {
157 Object value1 = PropertyUtils.getProperty( o1, property );
158 Object value2 = PropertyUtils.getProperty( o2, property );
159 return comparator.compare( value1, value2 );
160 }
161 catch ( IllegalAccessException iae ) {
162 throw new RuntimeException( "IllegalAccessException: " + iae.toString() );
163 }
164 catch ( InvocationTargetException ite ) {
165 throw new RuntimeException( "InvocationTargetException: " + ite.toString() );
166 }
167 catch ( NoSuchMethodException nsme ) {
168 throw new RuntimeException( "NoSuchMethodException: " + nsme.toString() );
169 }
170 }
171
172 /***
173 * Two <code>BeanComparator</code>'s are equals if and only if
174 * the wrapped comparators and the property names to be compared
175 * are equal.
176 * @param o Comparator to compare to
177 * @return whether the the comparators are equal or not
178 */
179 public boolean equals(Object o) {
180 if (this == o) {
181 return true;
182 }
183 if (!(o instanceof BeanComparator)) {
184 return false;
185 }
186
187 final BeanComparator beanComparator = (BeanComparator) o;
188
189 if (!comparator.equals(beanComparator.comparator)) {
190 return false;
191 }
192 if (property != null)
193 {
194 if (!property.equals(beanComparator.property)) {
195 return false;
196 }
197 }
198 else
199 {
200 return (beanComparator.property == null);
201 }
202
203 return true;
204 }
205
206 /***
207 * Hashcode compatible with equals.
208 * @return the hash code for this comparator
209 */
210 public int hashCode() {
211 int result;
212 result = comparator.hashCode();
213 return result;
214 }
215 }