I have this json and I want to be able to sort it by multiple field values of different types while retaining the previous sort order.
{
"code": "1603",
"description": "",
"score": 10,
"max": 100,
"effts": "2021-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "INACTIVE"
},
{
"code": "1604",
"description": "",
"score": 10,
"max": 100,
"effts": "2020-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "INACTIVE"
},
{
"code": "1600",
"description": "",
"score": 10,
"max": 100,
"effts": "2021-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
},
{
"code": "1606",
"description": "",
"score": 10,
"max": 100,
"effts": "2022-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
},
{
"code": "1601",
"description": "",
"score": 10,
"max": 100,
"effts": "2020-12-07T00:00:00",
"expDate": "2021-06-21",
"charityMaxCount": 1400000,
"charityUseCount": 938297,
"title": "",
"imageUrl": "",
"status": "ACTIVE"
}
]
The fields by which I should decide to sort it are given through another json:
{
"id": 1,
"field": "status",
"type": "string",
"sortMode": "ASC"
},
{
"id": 2,
"field": "expDate",
"type": "string",
"sortMode": "ASC"
}
]
I managed to achieve this by converting the json array to a list of Hashmap<String,Object>
and wrote a custom comparator. The problem is when I sort by status in ASC order which puts the ACTIVE entries at top, I don't want this order to get messed when I choose to sort it by another field like expDate for example.
Here is my code:
public String sort() throws JsonProcessingException {
List<TreeMap<String, String>> sortOrder = readSortOrder(sortOrderJson);
List<HashMap<String, Object>> payLoad = readPayLoad(payloadJson);
ObjectMapper objectMapper = new ObjectMapper();
if (sortOrder.size() > 1) {
for (TreeMap<String, String> map : sortOrder) {
if (map.get(Constants.SORT_MODE).equals(SortOrder.DSC.toString())) {
payLoad.sort(new MapComparator(map.get(Constants.FIELD)).reversed());
} else {
payLoad.sort(new MapComparator(map.get(Constants.FIELD)));
}
}
}
return objectMapper.writeValueAsString(payLoad);
}
public List<HashMap<String, Object>> readPayLoad(String jsonInput) {
ObjectMapper mapper = new ObjectMapper();
List<HashMap<String, Object>> jsonList = new ArrayList<>();
try {
HashMap[] payLoadDTOS = mapper.readValue(jsonInput, HashMap[].class);
jsonList = Arrays.asList(payLoadDTOS);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonList;
}
public List<TreeMap<String, String>> readSortOrder(String sortOrder) {
final ObjectMapper objectMapper = new ObjectMapper();
List<TreeMap<String, String>> jsonList = new ArrayList<>();
try {
TreeMap[] sortOrderDTOS = objectMapper.readValue(sortOrder, TreeMap[].class);
jsonList = Arrays.asList(sortOrderDTOS);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return jsonList;
}
And this as comparator:
public class MapComparator implements Comparator<Map<String, Object>> {
private final String key;
public MapComparator(String key) {
this.key = key;
}
@Override
public int compare(Map<String, Object> one, Map<String, Object> two) {
Object first = one.get(key);
Object second = two.get(key);
if (first instanceof String && second instanceof String) {
if ((isValidDate((String) first) && isValidDate((String) second))
|| (isValidDateTime((String) first) && isValidDateTime((String) second))) {
return DateTimeComparator.getInstance().compare(first, second);
} else {
return ((String) first).compareTo((String) second);
}
} else if (first instanceof Integer && second instanceof Integer) {
return ((Integer) first).compareTo((Integer) second);
}
return 0;
}
}
I think I should separate say ACTIVE and INACTIVE in two other collections and sort each then, but the fields by which I may conduct the separation could be dynamic and may change each time. How can I algorithmically handle this?