1. /*
  2. * Copyright 2001-2004 The Apache Software Foundation.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.beanutils;
  17. import java.io.Serializable;
  18. import java.util.Comparator;
  19. import org.apache.commons.beanutils.PropertyUtils;
  20. import org.apache.commons.collections.comparators.ComparableComparator;
  21. /**
  22. * <p>
  23. * This comparator compares two beans by the specified bean property.
  24. * It is also possible to compare beans based on nested, indexed,
  25. * combined, mapped bean properties. Please see the {@link PropertyUtilsBean}
  26. * documentation for all property name possibilities.
  27. *
  28. * </p><p>
  29. * <strong>Note:</strong> The BeanComparator passes the values of the specified
  30. * bean property to a ComparableComparator, if no comparator is
  31. * specified in the constructor. If you are comparing two beans based
  32. * on a property that could contain "null" values, a suitable <code>Comparator</code>
  33. * or <code>ComparatorChain</code> should be supplied in the constructor.
  34. * </p>
  35. *
  36. * @author <a href"mailto:epugh@upstate.com">Eric Pugh</a>
  37. * @author Tim O'Brien
  38. */
  39. public class BeanComparator implements Comparator, Serializable {
  40. private String property;
  41. private Comparator comparator;
  42. /**
  43. * <p>Constructs a Bean Comparator without a property set.
  44. * </p><p>
  45. * <strong>Note</strong> that this is intended to be used
  46. * only in bean-centric environments.
  47. * </p><p>
  48. * Until {@link #setProperty} is called with a non-null value.
  49. * this comparator will compare the Objects only.
  50. * </p>
  51. */
  52. public BeanComparator() {
  53. this( null );
  54. }
  55. /**
  56. * <p>Constructs a property-based comparator for beans.
  57. * This compares two beans by the property
  58. * specified in the property parameter. This constructor creates
  59. * a <code>BeanComparator</code> that uses a <code>ComparableComparator</code>
  60. * to compare the property values.
  61. * </p>
  62. *
  63. * <p>Passing "null" to this constructor will cause the BeanComparator
  64. * to compare objects based on natural order, that is
  65. * <code>java.lang.Comparable</code>.
  66. * </p>
  67. *
  68. * @param property String Name of a bean property, which may contain the
  69. * name of a simple, nested, indexed, mapped, or combined
  70. * property. See {@link PropertyUtilsBean} for property query language syntax.
  71. * If the property passed in is null then the actual objects will be compared
  72. */
  73. public BeanComparator( String property ) {
  74. this( property, ComparableComparator.getInstance() );
  75. }
  76. /**
  77. * Constructs a property-based comparator for beans.
  78. * This constructor creates
  79. * a BeanComparator that uses the supplied Comparator to compare
  80. * the property values.
  81. *
  82. * @param property Name of a bean property, can contain the name
  83. * of a simple, nested, indexed, mapped, or combined
  84. * property. See {@link PropertyUtilsBean} for property query language
  85. * syntax.
  86. * @param comparator BeanComparator will pass the values of the
  87. * specified bean property to this Comparator.
  88. * If your bean property is not a comparable or
  89. * contains null values, a suitable comparator
  90. * may be supplied in this constructor.
  91. */
  92. public BeanComparator( String property, Comparator comparator ) {
  93. setProperty( property );
  94. this.comparator = comparator;
  95. }
  96. /**
  97. * Sets the method to be called to compare two JavaBeans
  98. *
  99. * @param property String method name to call to compare
  100. * If the property passed in is null then the actual objects will be compared
  101. */
  102. public void setProperty( String property ) {
  103. this.property = property;
  104. }
  105. /**
  106. * Gets the property attribute of the BeanComparator
  107. *
  108. * @return String method name to call to compare.
  109. * A null value indicates that the actual objects will be compared
  110. */
  111. public String getProperty() {
  112. return property;
  113. }
  114. /**
  115. * Gets the Comparator being used to compare beans.
  116. */
  117. public Comparator getComparator() {
  118. return comparator;
  119. }
  120. /**
  121. * Compare two JavaBeans by their shared property.
  122. * If {@link #getProperty} is null then the actual objects will be compared.
  123. *
  124. * @param o1 Object The first bean to get data from to compare against
  125. * @param o2 Object The second bean to get data from to compare
  126. * @return int negative or positive based on order
  127. */
  128. public int compare( Object o1, Object o2 ) {
  129. if ( property == null ) {
  130. // compare the actual objects
  131. return comparator.compare( o1, o2 );
  132. }
  133. try {
  134. Object value1 = PropertyUtils.getProperty( o1, property );
  135. Object value2 = PropertyUtils.getProperty( o2, property );
  136. return comparator.compare( value1, value2 );
  137. }
  138. catch ( Exception e ) {
  139. throw new ClassCastException( e.toString() );
  140. }
  141. }
  142. /**
  143. * Two <code>BeanComparator</code>'s are equals if and only if
  144. * the wrapped comparators and the property names to be compared
  145. * are equal.
  146. */
  147. public boolean equals(Object o) {
  148. if (this == o) return true;
  149. if (!(o instanceof BeanComparator)) return false;
  150. final BeanComparator beanComparator = (BeanComparator) o;
  151. if (!comparator.equals(beanComparator.comparator)) return false;
  152. if (property != null)
  153. {
  154. if (!property.equals(beanComparator.property)) return false;
  155. }
  156. else
  157. {
  158. return (beanComparator.property == null);
  159. }
  160. return true;
  161. }
  162. /**
  163. * Hashcode compatible with equals.
  164. */
  165. public int hashCode() {
  166. int result;
  167. result = comparator.hashCode();
  168. return result;
  169. }
  170. }