View Single Post
Old 07-21-2004, 03:09 PM   #10 (permalink)
technobard
Centurion Nova Prime
 
technobard's Avatar
 
Join Date: May 2002
Location: Oak Park, IL (USA)
Posts: 287
technobard is on a distinguished road
Generic String Comparator

I spent the last few days in an Oracle Database Security class. I had a little free time in between and decided to see how much work would be required to do this sort thing. Surprisingly, not as much as I thought.

For anyone interested, StringComparator allows you to sort on any public member variable or method. I made some choices based on my own preferences here that could easily be coded a different way. (See code below)

The requirements are simple.
StringComparator strComp = new StringComparator(Object sample, String sortbyme, String sorttype);
creates the Comparator object. "sample" is an object of the type that will be sorted. "sortbyme" is the case-sensitive name of the field or method that will be used to drive the sort. "sorttype" is either "string" or "method" indicating the obvious. The fields and/or methods used for sorting must evaluate as a String. (I have to add code to prevent other types.)

The code could use a few checks here and there, but works fairly well so far in limited testing. I would appreciate any comments, suggestions, etc.

Code:
import java.util.*;
import java.lang.reflect.*;

public class StringComparator implements Comparator{
    Field[] publicFields;
    Method[] theMethods;
    Class[] parameterTypes;
    Vector methvec;
    Vector fieldvec;
    String sortBy = "";
    String sortType = "string";
    boolean nameMatch = true;
    int methodIndex = 0;
    
    /** Creates a new instance of StringComparator */
    public StringComparator() {
    }
        
    public StringComparator(Object sample, String sortbyme, String sorttype) {
        sortBy = sortbyme;
        sortType = sorttype;
        Class c0 = sample.getClass();  //get sample class
        methvec = new Vector();
        fieldvec = new Vector();
        String tempName = "";
        
        theMethods = c0.getMethods();
        for (int i = 0; i < theMethods.length; i++) {
            tempName = theMethods[i].getName();
            methvec.add(tempName);
            if (tempName.equals(sortBy)) {
                parameterTypes = theMethods[i].getParameterTypes();
                methodIndex = i;
            }
        }
        
        publicFields = c0.getFields();
        for (int i = 0; i < publicFields.length; i++) {
            fieldvec.add(publicFields[i].getName());
        }
        
        if (sortType.equals("string")) {
            nameMatch = fieldvec.contains(sortBy);
        }
        
        if (sortType.equals("method")) {
            nameMatch = methvec.contains(sortBy);
        }
        
    }  // end of constructor
    
    public boolean isValid() {
        return nameMatch;
    }
    
    public void setSortBy(String sortbyme) {
        sortBy = sortbyme;
    }
    
    public String getSortBy() {
        return sortBy;
    }
    
    public int compare(Object obj1, Object obj2) {
        Class c1 = obj1.getClass();
        Class c2 = obj2.getClass();
        String str1val = "";
        String str2val = "";
        
        if (sortType.equals("string")) {
            try {
                Field str1 = c1.getField(getSortBy());
                Field str2 = c2.getField(getSortBy());
                str1val = (String) str1.get(obj1);
                str2val = (String) str2.get(obj2);
            } catch (Exception e) {
                System.out.println(e);
            }
        }
        
        if (sortType.equals("method")) {
            
            try {
                str1val = (String) theMethods[methodIndex].invoke(obj1, parameterTypes);
                str2val = (String) theMethods[methodIndex].invoke(obj2, parameterTypes);
            } catch (IllegalAccessException e) {
                System.out.println(e);
            } catch (InvocationTargetException e) {
                System.out.println(e);
            }
        }
        
        return str1val.compareTo(str2val);
    }
}
I was concerned about overhead. So one of the choices I made was to pre-populate a lot of the metadata from the reflection api during construction of the object. This moved repetitive calls out of the actual compare() method. I will probably do some timing comparisons on say a 10,000 object array to see how it stacks up to a normal Comparator for the same task...when I get some more time anyway.
technobard is offline   Reply With Quote