001    package edu.nrao.sss.sort;
002    
003    import java.util.Comparator;
004    
005    /**
006     * A {@link SortKey sort key} and {@link Comparator comparator} that works with
007     * the {@code String}s returned by a method that is found reflectively.
008     * <p>
009     * Clients of this class must provide the name of a public, no argument, method
010     * that returns a {@code String} and that is present in classes of the
011     * parameterized type {@code T}.  The method created from that name is called
012     * on the objects to be compared, and the strings returned from those methods
013     * are what is actually compared.</p>
014     * <p>
015     * Because this class is a {@link SortKey}, you may configure its instances with
016     * a particular {@code SortOrder}.  Because it is a {@link StringSortKey}, you
017     * may tell it to ignore differences in case.  You may place instances of this
018     * class in a {@link CompoundComparator}.</p>
019     * <p>
020     * <b><u>Example</u></b><br/>
021     * Let there be a class, <tt>PostalAddress</tt>, that has the following
022     * attributes, each of which is a <tt>String</tt>:
023     * <tt>state, city, postalCode</tt>.  Furthermore, assume the normal convention
024     * for the getters (e.g., <tt>getCity()</tt>).  You could sort a collection of
025     * addresses by state, then city, then postal code, without writing any new
026     * classes by doing this:</p>
027     * <pre>
028     *   ReflectiveStringSortKey&lt;Address&gt; stateKey =
029     *     new ReflectiveStringSortKey&lt;Address&gt;("getState");
030     *     
031     *   ReflectiveStringSortKey&lt;Address&gt; cityKey =
032     *     new ReflectiveStringSortKey&lt;Address&gt;("getCity");
033     *     
034     *   ReflectiveStringSortKey&lt;Address&gt; codeKey =
035     *     new ReflectiveStringSortKey&lt;Address&gt;("getPostalCode");
036     *     
037     *   CompoundComparator&lt;Address&gt; comparator =
038     *     new CompoundComparator&lt;Address&gt;(stateKey, cityKey, codeKey);
039     *     
040     *   Collections.sort(myAddresses, comparator);
041     * </pre>
042     * <p>
043     * <b>Version Info:</b>
044     * <table style="margin-left:2em">
045     *   <tr><td>$Revision: 593 $</td></tr>
046     *   <tr><td>$Date: 2007-05-07 15:54:14 -0600 (Mon, 07 May 2007) $</td></tr>
047     *   <tr><td>$Author: dharland $</td></tr>
048     * </table></p>
049     * 
050     * @author David M. Harland
051     * @since 2007-05-04
052     */
053    public final class ReflectiveStringSortKey<T>
054      extends StringSortKey
055      implements Comparator<T>
056    {
057      private ReflectiveSortHelper<String, T> helper;
058      
059      /**
060       * Creates a new instance that will base its comparison on the {@code String}
061       * returned by the method with the given name.
062       *  
063       * @param methodName the name of a public, no argument, method that belongs
064       *                   to objects of type {@code T} and that returns a
065       *                   {@code String}.  If there is any trouble creating or
066       *                   calling the method with this name, it will be treated
067       *                   as if it returns a {@code String} of <i>null</i>.
068       */
069      public ReflectiveStringSortKey(String methodName)
070      {
071        helper = new ReflectiveSortHelper<String, T>(methodName, (String)null);
072      }
073      
074      /**
075       * Sets the name of the method used for making comparisons.
076       * 
077       * @param newMethodName the name of a public, no argument, method that belongs
078       *                      to objects of type {@code T} and that returns a
079       *                      {@code String}.  If there is any trouble creating or
080       *                      calling the method with this name, it will be treated
081       *                      as if it returns a {@code String} of <i>null</i>.
082       */
083      public void setMethodName(String newMethodName)
084      {
085        helper.setMethodName(newMethodName);
086      }
087      
088      /* (non-Javadoc)
089       * @see Comparator#compare(Object, Object)
090       */
091      public int compare(T o1, T o2)
092      {
093        return compareObjects(helper.getValue(o1), helper.getValue(o2));
094      }
095    }