1

Already posted questions doesn't have solution for mine because all other solution using POJO field to sort but case is no POJO as request/responses are dynamic json , hence posting I need to perform multi level [with multiple attributes] sorting. The sorting multiple attributes are coming dynamic from input request..

 Have created individual Comparator for each dataTypes like String,Numeric, etc

e.g. IntegerComparator

public class IntegerComparator implements <DTOObject> {
 @Override
public int compare(DTOObject o1, DTOObject o2){
    return o1.getAccountID()-o2.getAccountID();
 }
} //since my json response is dynamic. getter method is framed 
    dynamically based on input request tells which parameter to sort.

StringComparator:-

public class StringComparator implements <DTOObject> {
 @Override
public int compare(DTOObject o1, DTOObject o2){
    return o1.getActName()-o2.getActName();
 }
} // since my json response is dynamic. getter method is framed
     dynamically based on input request tells which parameter to sort.

Main Class:-

 public class AccountService {
 public SearchResponse accountFetch(){
  //To do
  List <JSONObject> resultList= someObject.fetchAcoount("12345678");
  // the resultList is dynamic JSON reponse,
   so no setter/getter method cannot be created
  Collections.sort(resultList, new IntegerComparatorimplements ());
  // how to invoke multi level sorting here as sorting attributes are 
     dynamic and upto N parameters
 }
 }

Problem

Since my json response is dynamic, getter method is framed dynamically in each comparator based on input request("responseParameters") tells which parameter to sort.

Now how to build composite comparators in runtime for multi level sorting? How to invoke all comparators for multi level sorting?

"responseParameters" in below sample request tells based on what parameter to sort, sequence of parameter to sort [multi level sort], datatype of that param etc for the json response.

Sample Request:-

{
  {
  "RequestOject":{
    "CUSTID": "100"
  },
 "responseParameters":[
    {
    "name":"NAME",
    "datatype":"String",
    "order":"asc",
    "sequence":1
    },
    {
    "name":"SYSTEM",
    "datatype":"int",
    "order":"asc",
    "sequence":2
    },
    {
    "name":"AGE",
    "datatype":"int",
    "order":"desc",
    "sequence":4
    },
    {
    "name":"TITLE",
    "datatype":"String",
    "order":"desc",
    "sequence":3
    },
upto... N parameters
    ]
 }
}

Note: sorting attributes are dynamic and upto 1... N paramters

Sample Response:-

 "ResponseObject":{
   "documents": [
     {
    "DETAIL":[
       {"CUSTID":"789"},
       {"ACCT":"SAV"},
       {"AGE":"22"}
      ],
    "SRC": {
      "SYSTEM":"IB",
      "TITLE":"PEM"
      },
   "SYSDATA":{
     "NAME":"MATT"
     }
     },
         {
    "DETAIL":[
       {"CUSTID":"522"},
       {"ACCT":"CUR"},
       {"AGE":"40"}
      ],
     "SRC": {
      "SYSTEM":"IB",
      "TITLE":"CON"
      },
   "SYSDATA":{
     "NAME":"JAMES"
     }
  }
 ]
}
Manu
  • 55
  • 2
  • 10
  • 1
    Possible duplicate of [sort a list of objects based on runtime property](https://stackoverflow.com/questions/13567526/sort-a-list-of-objects-based-on-runtime-property) – Progman May 12 '19 at 08:15

1 Answers1

0

I can't think of an easy way to do this. you have to create Comparator and pass it the json of attributes you want to sort by, and then create the dynamic code which does that. In addition you'll have to use reflection to get values of the fields given that you have only the field name as string.

I wrote an example, please notice:

  1. I don't know which Json lib you are using, I used GSON in my example
  2. There are some ways to use reflection, I used the shorter one but please refer to Reflection generic get field value to get your preferred way. If you have known range of values and want to avoid reflection it is also possible to use switch-case
  3. I left 2 TODOs
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;

import java.lang.reflect.Field;
import java.util.Comparator;

public class MyComprator implements Comparator<DTOObject> {

    private JsonArray params;

    public MyComprator(JsonArray params) {
        this.params = params;
        // TODO: Here possible to sort params by 'sequence' if needed
    }

    @Override
    public int compare(DTOObject o1, DTOObject o2) {
        for (int i = 0; i < params.size(); i++) {
            JsonObject param = params.get(i).getAsJsonObject();
            String fieldName = param.get("name").getAsString();
            String datatype = param.get("datatype").getAsString();
            int order = param.get("order").getAsString().equals("asc") ? 1 : -1;

            int compare = 0;

            if (datatype.equals("String")) {
                 compare = getField(o1, fieldName, String.class).compareTo(
                               getField(o2, fieldName, String.class));
            }
            else if (datatype.equals("int")) {
                compare = getField(o1, fieldName, Integer.class).compareTo(
                          getField(o2, fieldName, Integer.class));
            }

            if (compare != 0) {
                return compare * order;
            }
        }

        return 0;
    }

    private <T> T getField(DTOObject obj, String fieldName, Class<T> type) {
        try {
            // Use refelction
            Field field = DTOObject.class.getDeclaredField(fieldName);
            field.setAccessible(true);
            Object value = field.get(obj);
            return (T) value;
        }
        catch (NoSuchFieldException | IllegalAccessException e) {
            // TODO: Handle exception
            return null;
        }
    }
}
matanper
  • 881
  • 8
  • 24
  • @Mantanper. I dont have POJO since my response is dynamic always.. so I cant use this DTOObject.class.getDeclaredField(fieldName) – Manu May 16 '19 at 21:11
  • also Class type is not used anywhere? – Manu May 16 '19 at 21:12
  • Would you able to tell me. is there way we can have generic method to handle all Numeric data types [int,float,double] and one for string instead of creating multiple methods or classess?? – Manu May 16 '19 at 21:14
  • @Manu you used `DTOObject` in your post, it will be even easier to use a json object, since you won't need reflection. as for the numeric types you can just use `new BigDecimal(someString)` – matanper May 17 '19 at 13:04
  • Yes comapre to Integer.parse() or Double.parse().. now just using BigDecimal Api... method written for all numeric data type as.. public int comp( String s1, String s2){ BigDecimal v1= new BigDecimal (s1); BigDecimal v2= new BigDecimal (s2); v1.compareTo(v2)}. So using BigDecimal will it be performance hit?? – Manu May 20 '19 at 22:41
  • Depends on your use, in small scale and no arithmetic operations I don't belive you'll notice any difference. But try [googling](https://www.google.com/search?q=bigdecimal+performance) it and read about that – matanper May 21 '19 at 06:25