lundi 20 février 2017

Sort collection by property, given as a String

I'm implementing server side processing for jQuery datatables. For those of you who are unfamiliar with it, the plugin allows you to sort a column asc/desc, as well as search all columns with a single textbox. Since my list of objects is too large to send to the client, i need to replicate it's sorting functionality thru Java.

This is the object that i'm working with. Each field is a column in the client side table. All fields are either Strings or primitives/wrappers.

public class MyObject{

    String id;
    String productType;
    String productGroup;

    double totalSales;
    double salesVariance;

    int vendorId;
    String vendorName;
}

I need to be able to sort by any of the fields, ascending/descending, WITHOUT hard coding a comparator function for each field.

Given a string that represents a field name, how would I implement a generic sorting function?

My current solution is to process the list with Nashorn... :)

Java method that calls Nashorn:

/**
 * @param sortBy - field name
 * @param sortDirection - asc/desc
 */
public void applyFilteringChanges(List<MyObject> myObjects, String sortBy, String sortDirection) throws Exception{

    Invocable invocable = (Invocable) engine;
    invocable.invokeFunction("sortObjects", myObjects, sortBy, sortDirection);

}

Nashorn code:

function sortObjects(myObjects, prop, direction) {
    var dir = (direction === 'asc') ? 1 : -1;
    myObjects.sort(function(a,b){
        return compare(a,b,prop) * dir;
    })
};

function compare(a,b,prop){
    if(a[prop] < b[prop])
        return -1;
    else if(a[prop] > b[prop])
        return 1;
    return 0;
}

I also dabbled in Reflection, but it's incomplete at the moment.

public void applyFilteringChanges(List<MyObject> myObjects, String sortBy, String sortDirection) throws Exception{

        myObjects.sort((s1,s2)->{
            Field field;
            try {
                field = s1.getClass().getDeclaredField(sortBy);
                Class<?> type = field.getType();
                if(type.isPrimitive()){
                    //deal with primitive
                }else{
                    Comparable o1FieldValue = (Comparable) field.get(s1);
                    Comparable o2FieldValue = (Comparable) field.get(s2);
                    return o1FieldValue.compareTo(o2FieldValue);
                }

            } catch (Exception e) {
                e.printStackTrace();
            }

            return 0;
        });

    }

Both of my approaches feel like hacks, is there a standard way to accomplish this?





Aucun commentaire:

Enregistrer un commentaire