views:

41

answers:

4

I have a list of objects and I want to sort by passing object's field name and order(ascending or descending). For example: my object is,

class Person{
         private String name;
         private String age;
        //getters and setters
         ..........
}


I will pass (List personList , String "name" and boolean isAscending) to an API method for sorting the personList. I can implement this by writing implementation class for Comparator but I want to have a generic method.

That is if I have Address object, I should be able to sort address object list by its field name (for ex: streetName).

Basically I am looking for a generic sort method to sort any kind of list. Any such APIs available?

A: 

There is a functional barrier to passing a "string" to identify a field. But if there was a generic way api available it would probably ask you to use a map or to have a get("fieldname") method to get the field it sorts on.

I would use a Comparator instead of Comparable if you are going to change the way you sort.

cjavapro
+3  A: 

I'm assuming you actually have getters and setters for the properties you want to use. Using the private fields directly is probably a bad idea anyways.

You can use BeanComparator from commons-beanutils. To sort ascending, use new BeanComparator("name"), for descending new BeanCompartor("name", Collections.reverseOrder())

Wouter Coekaerts
A: 

Seems like you need a reflection API.

import java.lang.reflect.Field;

String fieldValue(Object obj, String fieldName) {
     Class c = obj.class;
     Field f = c.getField(fieldName);
     return (String)f.get(obj);
}

There may be some leak of typing, but you can always fix it manually by checking field's type with f.getType().

Andrei
A: 

@Wouter Coekaerts's answer is the simplest way to do this.

However!

The problem with any solution that uses reflection under the hood is that reflective operations are significantly more expensive than their non-reflective (compiled code) equivalents. Typically 1 to 2 orders of magnitude more expensive.

In your case, the comparator is going to be called O(NlogN) times each time you sort the object list. If your application is going to be sorting large lists ... or small lists lots of times ... the overheads of using a reflective comparator could make a big difference to your application's overall performance.

If performance turns out to be an issue (and profiling tells you that the reflective comparator is at fault), the alternatives are:

  • Write the comparators by hand. This is the simplest and most performant solution, whether or not you think it is elegant.

  • Use run-time source code generation to generate comparator classes and then compile and load them.

  • Use run-time bytecode generation to generate comparator classes and load them.

These could be combined with a lookup / caching mechanism that stores the comparators in a hash table using a key that combines the class and the field name. (A cache is essential if you use the code generation approach. But you still need to consider whether any given generated comparator will be used often enough to justify the large once-off overhead of generating/compiling/loading a class.)

Stephen C