2012-12-31

Null-safe bean comparator for commons-beans

Hacky solution, catching the NPE's. I have coded a clean solution, but I haven't tested it…

package com.rapidlime.pohlidame;


import java.lang.reflect.InvocationTargetException;
import java.util.Comparator;
import org.apache.commons.beanutils.BeanComparator;
import org.apache.commons.beanutils.NestedNullException;
import org.apache.commons.beanutils.PropertyUtils;



/**
 *
 * @author Ondrej Zizka
 */
public class NullSafeUglyBeanComparator extends BeanComparator
{

    public NullSafeUglyBeanComparator( String property, Comparator comparator ) {
      super( property, comparator );
    }



    private static Object getNullSafeProperty( Object o1, String property )
    throws IllegalAccessException, InvocationTargetException,  NoSuchMethodException
    {
      Object val;
      try {
        val = PropertyUtils.getProperty( o1, property );
      }
      catch( NestedNullException ex ){
        val = null;
      }
      return val;
    }

    private static final boolean NULL_GOES_LAST = true;


    /**
     * Compare two JavaBeans by their shared property.
     * If {@link #getProperty} is null then the actual objects will be compared.
     *
     * @param  o1 Object The first bean to get data from to compare against
     * @param  o2 Object The second bean to get data from to compare
     * @return int negative or positive based on order
     */
    @Override
    public int compare( Object o1, Object o2 ) {

        final String property = getProperty();
        final Comparator comparator = getComparator();

        if ( property == null ) {
            // compare the actual objects
            return comparator.compare( o1, o2 );
        }

        try {
            //Object value1 = PropertyUtils.getProperty( o1, property );
            //Object value2 = PropertyUtils.getProperty( o2, property );
            Object value1 = getNullSafeProperty( o1, property );
            Object value2 = getNullSafeProperty( o2, property );
            if( null == value1 && null == value2 ) return 0;
            if( null == value1 ) return NULL_GOES_LAST ? +1 : -1;
            if( null == value2 ) return NULL_GOES_LAST ? +1 : -1;
            return comparator.compare( value1, value2 );
        }
        catch ( IllegalAccessException iae ) {
            throw new RuntimeException( "IllegalAccessException: " + iae.toString() );
        }
        catch ( InvocationTargetException ite ) {
            throw new RuntimeException( "InvocationTargetException: " + ite.toString() );
        }
        catch ( NoSuchMethodException nsme ) {
            throw new RuntimeException( "NoSuchMethodException: " + nsme.toString() );
        }
    }



}// class NullSafeBeanComparator

0