3.10. Comparing Beans

Problem

You need to sort or compare beans by a bean property.

Solution

Use BeanComparator to compare two beans using a bean property, which can be simple, nested, indexed, or mapped. BeanComparator obtains the value of the same bean property from two objects and, by default, compares the properties with a ComparableComparator. The following example sorts a list of Country objects using a BeanComparator and the default ComparableComparator:

import java.util.*;
import org.apache.commons.beanutils.BeanComparator;

Country country1 = new Country( );
country1.setName( "India" );

Country country2 = new Country( );
country2.setName( "Pakistan" );

Country country3 = new Country( );
country3.setName( "Afghanistan" );

// Create a List of Country objects
Country[] countryArray = new Country[] { country1, country2, country3 };
List countryList = Arrays.asList( countryArray );

// Sort countries by name
               Comparator nameCompare = new BeanComparator( "name" );
               Collections.sort( countryList, nameCompare );

System.out.println( "Sorted Countries:" );
Iterator countryIterator = countryList.iterator( );
while( countryIterator.hasNext( ) ) {
    Country country = (Country) countryIterator.next( );
    System.out.println( "	Country: " + country.getName( ) );
}

This code creates three Country objects with different names, places the Country objects into a list, and sorts this list with a BeanComparator configured to compare by the bean property name. This code executes and prints the sorted list of countries:

Sorted Countries:
    Country: Afghanistan
    Country: India
    Country: Pakistan

Discussion

The previous example demonstrated the default behavior of BeanComparator; when a BeanComparator is constructed with only one parameter, it uses a ComparableComparator to compare the values of the properties it retrieves. You can also construct a BeanComparator with an instance of Comparator; in this case, BeanComparator decorates another Comparator, retrieving the values of a property and passing these values on to an instance of Comparator. The following example demonstrates the use of BeanComparator with a custom Comparator implementation. This example involves two objects shown in Figure 3-6: ElectricVehicle and Engine.

Objects involved in a sorting example

Figure 3-6. Objects involved in a sorting example

An application needs to sort ElectricVehicle objects by efficiency, and, in this contrived example, efficiency is defined as the number of miles per gallon times the percentage of electric operation; an 80% electric hybrid vehicle is more efficient than a 25% electric hybrid vehicle with the same mileage because of reduced emissions. The code fragments shown in Example 3-5 sort a collection of beans by wrapping a custom Comparator with a BeanComparator.

Example 3-5. Decorating a Comparator with a BeanComparator

import java.util.*;
import org.apache.commons.beanutils.BeanComparator;

// Create Engines
Engine engine1 = new Engine( );
engine1.setMilesGallon( new Integer(60) );
engine1.setPercentElectric( new Integer(50) );

Engine engine2 = new Engine( );
engine2.setMilesGallon( new Integer(90) );
engine2.setPercentElectric( new Integer(50) );

Engine engine3 = new Engine( );
engine3.setMilesGallon( new Integer(65) );
engine3.setPercentElectric( new Integer(45) );

// Create Vehicles
ElectricVehicle vehicle1 = new ElectricVehicle( );
vehicle1.setMake( "Toy Yoda" );
vehicle1.setModel( "Electro" );
vehicle1.setYear( 2005 );
vehicle1.setEngine( engine1 );

ElectricVehicle vehicle2 = new ElectricVehicle( );
vehicle2.setMake( "Fjord" );
vehicle2.setModel( "Photon" );
vehicle2.setYear( 2004 );
vehicle2.setEngine( engine2 );

ElectricVehicle vehicle3 = new ElectricVehicle( );
vehicle3.setMake( "Ford" );
vehicle3.setModel( "Electric Pinto" );
vehicle3.setYear( 2005 );
vehicle3.setEngine( engine3 );

// Create List of Vehicles
List vehicles = new ArrayList( );
vehicle.add( vehicle1 );
vehicle.add( vehicle2 );
vehicle.add( vehicle3 );

// Define Engine Comparison Logic in an Anonymous inner class
// which implements the Comparator interface
Comparator engineCompare = new Comparator( ) {
    public int compare(Object o1, Object o2) {
        Engine engine1 = (Engine) o1;
        Engine engine2 = (Engine) o2;

        int engine1Temp = engine1.getMilesGallon( ).intValue( ) *
                        engine1.getPercentElectric( ).intValue( );
        int engine2Temp = engine2.getMilesGallon( ).intValue( ) *
                        engine2.getPercentElectric( ).intValue( );

        Integer engine1Factor = new Integer( engine1Temp );
        Integer engine2Factor = new Integer( engine2Temp );

        return engine1Factor.compareTo( engine2Factor );
    }
}

Comparator vehicleCompare = new BeanComparator( "engine", engineCompare );
                  Collections.sort( vehicles, vehicleCompare );

// Print Sorted Results
System.out.println( "Vehicles Sorted by Efficiency:" );
Iterator vehicleIter = vehicles.iterator( );
while( vehicleIter.hasNext( ) ) {
    ElectricVehicle vehicle = (ElectricVehicle) vehicleIter.next( );
    System.out.println( "	Vehicle: " + vehicle.getModel( ) + ", " +
        vehicle.getEngine( ).getMilesGallon( ) + " MPG, " + 
        vehicle.getEngine( ).getPercentElectric( ) + "% Electric" );
}

engineCompare contains the logic used to sort vehicles by efficiency, and BeanComparator supplies the engine properties to this Comparator implementation. This previous example creates three vehicles and sorts the vehicles in order of efficiency; the following results are printed:

Vehicles Sorted by Efficiency:
    Vehicle: Photon, 90 MPG, 50% Electric
    Vehicle: Electro, 60 MPG, 50% Electric
    Vehicle: Electric Pinto, 65 MPG, 45% Electric

See Also

Chapter 4 provides examples of various Comparator implementations, which can be used to decorate other comparators. One Comparator in particular is important if you plan to sort beans on a bean property, which could be null. If a bean property could be null, make sure to pass a NullComparator to BeanComparator; otherwise, ComparableComparator will throw a NullPointerException if a property value is null. Recipe 4.5 discusses techniques for decorating a Comparator with NullComparator.

Recipe 3.15 discusses a BeanPredicate object that can be used to validate beans. The BeanPredicate is similar to the BeanComparator as it decorates another instance of Predicate, providing access to a bean property.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.138.35.255