Reputation: 11035
I have a JSON
with some key-value
pairs. I need to pick up by name and process it's value differently. The oder of the process should be same order as the keys listed in the JSON
(JSON
is unknown, only knows it will have some key and corresponding value, so cant not know the order outside of the JSON
).
Simplified sample usage:
String jsonData = "{key1:{some other data}, key2:{sub-key:sub-value}}";
val jsonObject = JSONObject(jsonData)
val names = jsonObject.keys()
if (names.hasNext()) {
val key = names.next()
val valueJson = jsonData.optString(key)
val gson = Gson()
val resultList = ArrayList<Data> () // result should keep the order as the keys in the json
if (key == "key1") {
val parsedResult = gson.fromJson <POJO_1> (valueJson, POJO_1::class.java)
resultList.add(processDataFromKey1(parsedResult))
} else if (key == "key2") {
val parsedResult = gson.fromJson <POJO_2> (valueJson, POJO_2::class.java)
resultList.add(processDataFromKey2(parsedResult))
}
}
The problem is the jsonObject.keys()
the order of the keys is undefined
.
So how to preserve the order of the keys from the JSON
string (don't want to add dependency javax.json:javax.json-api
)
Upvotes: 0
Views: 2444
Reputation: 61
Another thing you can do is refer to the String jsonData in your example and rebuild the order.
Something like:
JSONObject json = new JSONObject(jsonData);
Iterator<String> keys = json.keys();
List<KeyOrder> ordering = new ArrayList();
while(keys.hasNext()) {
String key = keys.next();
int loc = jsonData.indexOf('"' + key + '"');
ordering.add(new KeyOrder(loc, key));
}
Collections.sort(ordering);
for(KeyOrder order: ordering) {
Object value = json.get(order.getKey());
// process the key and value
}
public class KeyOrder implements Comparable<KeyOrder> {
private int order;
private String key;
public KeyOrder(int order, String key) {
this.order = order;
this.key = key;
}
@Override
public int compareTo(KeyOrder o) {
return order - o.getOrder();
}
private int getOrder() {
return order;
}
public String getKey() {
return key;
}
}
Upvotes: 0
Reputation: 38690
org.json.JSONObject
internally uses HashMap
. They even added some comment to it:
HashMap
is used on purpose to ensure that elements are unordered by the specification.JSON
tends to be a portable transfer format to allows the container implementations to rearrange their items for a faster element retrieval based on associative access. Therefore, an implementation mustn't rely on the order of the item.
Use Gson
. It uses com.google.gson.internal.LinkedTreeMap
implementation for Map
. From it's documentation:
A map of comparable keys to values. Unlike
TreeMap
, this class uses insertion order for iteration order. Comparison order is only used as an optimization for efficient insertion and removal.
This implementation was derived from Android 4.1's TreeMap class.
So, for below JSON
payload
:
{
"status": "status",
"date": "01/10/2019",
"abc": {
"Field1": "value1",
"key": "value2"
},
"rgj": {
"key": "value2",
"Field1": "value3"
},
"name": "Rick"
}
This example app:
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.util.Map;
public class GsonApp {
public static void main(String[] args) throws Exception {
File jsonFile = new File("./resource/test.json").getAbsoluteFile();
Gson gson = new GsonBuilder().create();
Type type = new TypeToken<Map<String, Object>>() {
}.getType();
Map<String, Object> map = gson.fromJson(new FileReader(jsonFile), type);
map.forEach((k, v) -> {
if (v instanceof Map) {
System.out.println(k);
((Map) v).forEach((k1, v1) -> System.out.println(" " + k1 + " => " + v1));
} else {
System.out.println(k + " => " + v);
}
});
}
}
Prints:
status => status
date => 01/10/2019
abc
Field1 => value1
key => value2
rgj
key => value2
Field1 => value3
name => Rick
Notice that key
and Field1
are in different order in abc
and rgj
objects.
Upvotes: 2
Reputation: 1801
you could use jsonparser rather than jsonreader so you control the event flow. See https://docs.oracle.com/javaee/7/api/javax/json/stream/JsonParser.html
Note that your question is neither kotlin nor gson specific.
Upvotes: 1