Dynamically Generated Comparators
2 posts in topic
Flat View  Flat View
TOPIC ACTIONS:
 

Posted By:   Wayne_Kidd
Posted On:   Thursday, February 12, 2004 10:01 AM

I have often wondered whether anyone has developed a dynamic sorter that generates a comparator based on a class name and a list of javabean properties (field names) and a corresponding list of ascending / descending booleans. This would allow you to sort anything that was a javabean into any order without constructing a new type (although I suspect there is an inner class here somewhere). Does anyone know of such a thing?

Wayne

Re: Dynamically Generated Comparators

Posted By:   Sathiya_Shunmugasundaram  
Posted On:   Friday, April 30, 2004 08:21 AM

I have created this Code. Feel free to use or pass it on.

Usege is like this. Create an array of Strings that are properties of your JavaBean. --------------
String[] sortFields = new String[]{"classVal", "brand", "model"};
GenericComparator comp = new GenericComparator(sortFields, true);
Collections.sort(yourCollection, comp);

will work for sure.

Let me know if it is helpful.

The requirement is that all properties must implement comparable interface. All wrapper classes and String do this. hence it should not be a problem. In case you have a property that is not comparable, add a method to this class like I have added one for GregorianCalendar which does not implement Comparable and take care of the return value. Also add it to my exludedClasses Collection like this

excludedClasses.add(GregorianCalendar.class);

public int compareValues(GregorianCalendar gc1, GregorianCalendar gc2){}


----------------

import java.util.Comparator;
import org.apache.commons.beanutils.PropertyUtils;
import java.lang.reflect.*;
import org.apache.log4j.Logger;
import java.util.*;
import java.util.Calendar;

/**
*

Title: RtvCmRs


*

Description: Rtv/Cm Reconsiliation Project


*

Copyright: Copyright (c) 2003 Circuit City


*

Company: Circuit City


* @author Sathiya Shunmugasundaram
* @version 1.0
*/

public class GenericComparator implements Comparator {


private String[] sortFields = null;

private Collection supportedClasses = new ArrayList();
private HashMap defaultValues = new HashMap();
private Collection excludedClasses = new ArrayList();

boolean ascending = false;

Logger logger = null;

public GenericComparator(String[] sortFields, boolean ascending)
{
this.sortFields = sortFields;
this.ascending = ascending;
buildSupportedClasses();
setupDefaultValues();
buildExcludedClasses();
}

private void buildSupportedClasses()
{
supportedClasses.add(Integer.class);
supportedClasses.add(Long.class);
supportedClasses.add(Double.class);
supportedClasses.add(Float.class);
supportedClasses.add(Byte.class);
supportedClasses.add(Short.class);
supportedClasses.add(String.class);
}

private void buildExcludedClasses()
{
excludedClasses.add(GregorianCalendar.class);
}
private void setupDefaultValues()
{
defaultValues.put(Integer.class, new Integer(0));
defaultValues.put(Long.class, new Long(0));
defaultValues.put(Double.class, new Double(0));
defaultValues.put(Float.class, new Float(0));
byte b = 0;
defaultValues.put(Byte.class, new Byte(b));
short s = 0;
defaultValues.put(Short.class, new Short(s));
defaultValues.put(String.class, "");
GregorianCalendar defaultDate = new GregorianCalendar(1970, 0, 1);
defaultValues.put(GregorianCalendar.class, defaultDate);
defaultValues.put(Calendar.class, defaultDate);
}

public int compare(Object o1, Object o2)
{
int ret = compareit(o1, o2);
return ret;
}


public int compareit(Object o1, Object o2) {

if(!o1.getClass().equals(o2.getClass()))
{
throw new RuntimeException("The objects compared are not of same class");
}
if(!verifyProperties(o1))
{
throw new RuntimeException("The properties array passed to comparator has one or more invalid properties");
}
int length = sortFields.length;
for(int i=0; i< length; i++)
{
String property = sortFields[i];
Object value1 = getValue(property, o1);
Object value2 = getValue(property, o2);
if(value1 == null || value2 == null)
{
return 0;
}
int compared = compareValues(value1, value2);
if(compared == 0)
continue;
else
{
if(ascending)
return compared;
else
return (-compared);
}
}
return 0;
}

public String[] getSortFields() {
return sortFields;
}
public void setSortFields(String[] sortFields) {
this.sortFields = sortFields;
}

private boolean verifyProperties(Object o)
{
if(sortFields == null || sortFields.length == 0)
{
throw new RuntimeException("sortFileds must be initialized with a non empty array");
}
int length = sortFields.length;
for( int i=0; i {
String property = sortFields[i];
try {
Object value = PropertyUtils.getProperty(o, property);
if(!isComparable(value))
{
printError("Property " + property + " does not implement Comparable interface");
return false;
}
}
catch (Exception ex) {
printError("Error in getting property " + property + " " + ex.getMessage());
return false;
}
}
return true;
}

private void printError(String msg) {
if(logger != null)
{
logger.error(msg);
}
else
{
System.err.println(msg);
}
}

public Object getValue(String property, Object o) {
try {
Object value = PropertyUtils.getProperty(o, property);
if(value == null)
{
Class cls = PropertyUtils.getPropertyType(o, property);
value = defaultValues.get(cls);
}
return value;
}
catch (Exception ex) {
return null;
}
}

protected int compareValues(Object obj1, Object obj2) {

if (this.excludedClasses.contains(obj1.getClass()))
{
return compareExcludedClasses(obj1, obj2);
}
try {
Class clazz = obj1.getClass();
Class[] params = new Class[] {
Object.class};
Method compareToMethod = clazz.getMethod("compareTo", params);
Object[] arg = new Object[] {obj2};
Object o = compareToMethod.invoke(obj1, arg);;
Integer ret = (Integer) o;
if(ret != null)
return ret.intValue();
}
catch (Exception ex) {
printError(ex.getMessage());
}
return 0;
}

protected int compareExcludedClasses(Object obj1, Object obj2)
{
try {
Class clazz = this.getClass();
Class[] params = new Class[] {
obj1.getClass(), obj1.getClass()};
Method compareToMethod = clazz.getMethod("compareValues", params);
Object[] arg = new Object[] {obj1, obj2};
Object o = compareToMethod.invoke(this, arg);
Integer ret = (Integer) o;
if(ret != null)
return ret.intValue();
}
catch (Exception ex) {
printError(ex.getMessage());
}
return 0;
}

public void setLogger(Logger logger) {
this.logger = logger;
}

private boolean isComparable(Object o)
{

if(excludedClasses.contains(o.getClass()))
return true;
boolean implementsComparable = false;
Class clazz = o.getClass();
Class[] interfaces = clazz.getInterfaces();
int length = interfaces.length;
for(int i=0; i< interfaces.length; i++)
{
if(interfaces[i].equals(Comparable.class))
{
return true;
}
}
return false;
}

public int compareValues(GregorianCalendar gc1, GregorianCalendar gc2)
{
int year1 = gc1.get(Calendar.YEAR);
int month1 = gc1.get(Calendar.MONTH);
int day1 = gc1.get(Calendar.DATE);
int year2 = gc2.get(Calendar.YEAR);
int month2 = gc2.get(Calendar.MONTH);
int day2 = gc2.get(Calendar.DATE);
if(year1 > year2)
return 1;
else if(year1 < year2)
return -1;
else
{
if(month1 > month2)
return 1;
else if(month1 < month2 )
return -1;
else
{
if(day1 > day2)
return 1;
else if(day1 < day2)
return -1;
else
return 0;
}
}
}
}

Re: Dynamically Generated Comparators

Posted By:   faiz_nc  
Posted On:   Sunday, March 28, 2004 07:52 AM

Hi

You can achieve your task using java reflection mechanism. Depending upon the property name u supply, u can sort it.
Just get the class of the property and do it. It is really simple. I am giving sample code which would achieve your task.

Ideally the below code will be in the compare method of a class implementing Comparator interface. compare(Object obj1, Object obj2)




Class c = obj1.getClass();
BeanInfo info = Introspector.getBeanInfo( c );
PropertyDescriptor pd [] = info.getPropertyDescriptors();
for( int i=0;i{

If( pd[i].getName().equals("yourproperty") )
{

if( pd[i].getPropertyType() == String.class )
{
Method method = pd[i].getReadMethod();

String str1 = ( String )method.invoke( o, new Object[]{} );
/*
similarly get the property value for the next object obj2 and do the sorting
*/
}
}
}
About | Sitemap | Contact