Keep the order of the JSON keys during JSON conversion to CSV
There are (hacky) ways to do it ... but you shouldn't.
In JSON, an object is defined thus:
An object is an unordered set of name/value pairs.
See http://json.org.
Most implementations of JSON make no effort to preserve the order of an object's name/value pairs, since it is (by definition) not significant.
If you want order to be preserved, you need to redefine your data structure; e.g.
{
"items":
[
[
{"WR":"qwe"},
{"QU":"asd"},
{"QA":"end"},
{"WO":"hasd"},
{"NO":"qwer"}
],
]
}
or more simply:
{
"items":
[
{"WR":"qwe"},
{"QU":"asd"},
{"QA":"end"},
{"WO":"hasd"},
{"NO":"qwer"}
]
}
FOLLOWUP
Thanks for the info, but I have no choice but to use JSON in my application and my application needs to keep the order of the keys regardless of the definition of JSON object... I am not allowed to change the format of the JSON file as well...
You need to have a hard conversation with whoever designed that file structure and won't let you change it. It is / they are plain wrong. You need to convince them.
If they really won't let you change it:
- You should insist on not calling it JSON ... 'cos it isn't.
- You should point out that you are going to have to write / modify code specially to handle this "not JSON" format ... unless you can find some JSON implementation that preserves the order. If they are a paying client, make sure that they pay for this extra work you have to do.
- You should point out that if the "not JSON" needs to be used by some other tool, it is going to be problematic. Indeed, this problem will occur over and over ...
This kind of thing as really bad. On the one hand, your software will be violating a well established / long standing specification that is designed to promote interoperability. On the other hand, the nit-wits who designed this lame (not JSON!) file format are probably slagging off other people's systems etc 'cos the systems cannot cope with their nonsense.
UPDATE
It is also worth reading what the JSON RFC (RFC 7159) says on this subject. Here are some excerpts:
In the years since the publication of RFC 4627, JSON has found very wide use. This experience has revealed certain patterns, which, while allowed by its specifications, have caused interoperability problems.
JavaScript Object Notation (JSON) is a text format for the serialization of structured data. ...
JSON can represent four primitive types (strings, numbers, booleans, and null) and two structured types (objects and arrays).
An object is an unordered collection of zero or more name/value pairs, where a name is a string and a value is a string, number, boolean, null, object, or array.
JSON parsing libraries have been observed to differ as to whether or not they make the ordering of object members visible to calling software. Implementations whose behavior does not depend on member ordering will be interoperable in the sense that they will not be affected by these differences.
JSONObject.java
takes whatever map you pass. It may be LinkedHashMap
or TreeMap
and it will take hashmap
only when the map is null .
Here is the constructor of JSONObject.java
class that will do the checking of map.
public JSONObject(Map paramMap)
{
this.map = (paramMap == null ? new HashMap() : paramMap);
}
So before building a json object construct LinkedHashMap
and then pass it to the constructor like this ,
LinkedHashMap<String, String> jsonOrderedMap = new LinkedHashMap<String, String>();
jsonOrderedMap.put("1","red");
jsonOrderedMap.put("2","blue");
jsonOrderedMap.put("3","green");
JSONObject orderedJson = new JSONObject(jsonOrderedMap);
JSONArray jsonArray = new JSONArray(Arrays.asList(orderedJson));
System.out.println("Ordered JSON Fianl CSV :: "+CDL.toString(jsonArray));
So there is no need to change the JSONObject.java
class . Hope it helps somebody .
It is quite simple to maintain order. I had the same problem with maintaining the order from DB layer to UI Layer.
Open JSONObject.java file. It internally uses HashMap which doesn't maintain the order.
Change it to LinkedHashMap:
//this.map = new HashMap();
this.map = new LinkedHashMap();
This worked for me. Let me know in the comments. I suggest the JSON library itself should have another JSONObject class which maintains order, like JSONOrderdObject.java. I am very poor in choosing the names.
Another hacky solution using reflect:
JSONObject json = new JSONObject();
Field map = json.getClass().getDeclaredField("map");
map.setAccessible(true);//because the field is private final...
map.set(json, new LinkedHashMap<>());
map.setAccessible(false);//return flag