View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    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             // compare the actual objects
    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 }