Posted under Java
Permalink
Tags Bean, Cojen, Compare, Introspection, Java, Sort, Tip
Whilst this can be done with the Reflection API, there are standard APIs that do this for Beans and which are therefore a better choice.
java.beans.beaninfo is a standard API for bean introspection. Better still for many applications is the Apache Commons BeanUtils library.
This provides a really simple interface for many operations. For example, get/set of simple bean properties dynamically is a single call as in this example :-
Employee employee = ...; String firstName = (String) PropertyUtils.getSimpleProperty(employee, "firstName"); String lastName = (String) PropertyUtils.getSimpleProperty(employee, "lastName"); ... manipulate the values ... PropertyUtils.setSimpleProperty(employee, "firstName", firstName); PropertyUtils.setSimpleProperty(employee, "lastName", lastName);
One of my requirements was a dynamic sort comparator for use in sorting JSF tables by any column. A static comparator is fast, but messy, as you need to hard code switch statements etc. for the property to be compared. BeanUtils has a better option and can create a dynamic comparator for you as in the following code fragment from here :-
List tvShows = new ArrayList< WorldsGreatestTVShow>(); //group (sort) by actor BeanComparator actorComparator = new BeanComparator("actorName"); Collections.sort(tvShows, actorComparator); //group (sort) by producer BeanComparator producerComparator = new BeanComparator("producerName"); Collections.sort(tvShows, producerComparator);
However, there is a performance hit with using this – one comparison cited 16ms using a hard coded static comparator, compared to 400ms using the BeanUtils BeanComparator. Always one to strive for perfection, I said to myself “why can’t I have both” – i.e. a dynamically created comparator for no effort but which performs as well as a static one? Well, after a bit of searching I found one in the form of the Cojen Project. This is a project aimed at supporting dynamic bytecode generation and disassembly. However, the project also provides a number of powerful utility classes which use the bytecode generation to create fast dynamic Bean Comparators with the same peformance as a statically coded comparator, perform fast Bean Property Introspection, and fast Pattern Matching.
Here is an example comparator which orders threads by name, thread group name, and reverse priority :-
Comparator c = BeanComparator.forClass(Thread.class) .orderBy("name") .orderBy("threadGroup.name") .orderBy("-priority");
I particularly love the fact that the customising methods e.g. orderBy return the comparator instance so that you can chain them together as above. Sorting by multiple properties is supported as the above example shows. All the generated objects are fully serializable. I also love the fact that you can prefix a property name with a minus sign to reverse the comparison order for that orderBy, which is great for toggling column sort orders with JSF etc. A brief test had it working correctly in no time, and it does indeed appear to be just as fast as a static comparator and very flexible. In future, I would make Cojen my first port of call for bean pattern matching / introspection / comparison without hesitation, and then look at Apache Commons BeanUtils only if Cojen couldn’t do what I needed, then failing that java.beans.beaninfo or finally the raw reflection API.
I really can have my cake and eat it! Sex on a stick!