11

I need to create constant json string or a json sorted on keys. What do I mean by constant json string? Please look into following code sample, which I created.

My Code 1:

public class GsonTest
{
    class DataObject {

        private int data1 = 100;
        private String data2 = "hello";

    }   


    public static void main(String[] args)
    {
        GsonTest obj=new GsonTest();
        DataObject obj2 = obj.new DataObject();
        Gson gson = new Gson();

        String json = gson.toJson(obj2);
        System.out.println(json);
    }
}

Output 1:

{"data1":100,"data2":"hello"}

My Code 2:

public class GsonTest
{
    class DataObject {
        private String data2 = "hello";
        private int data1 = 100;


    }   


    public static void main(String[] args)
    {
        GsonTest obj=new GsonTest();
        DataObject obj2 = obj.new DataObject();
        Gson gson = new Gson();

        String json = gson.toJson(obj2);
        System.out.println(json);
    }
}

Output 2:

{"data2":"hello","data1":100}

If you see, if I switch variables (data1 & data2 in DataObject class), I get different json. My objective to get same json, even if somebody changes position of the class variables. I get it when somebody adds new variables, json would change. But json shouldn't change when variables are moved around. So, my objective is to get standard json, possibly in sorted keys order for same class. If there is nested json, then it should be sorted in the nested structure.

Expected output on run of both the codes:

{"data1":100,"data2":"hello"}  //sorted on keys!! Here keys are data1 & data2

I understand, I need to change something in String json = gson.toJson(obj2); line, but what do I have to do?

Why I need them to be order?

I need to encode the json string and then pass it to another function. If I change the order of keys, even though value remain intact, the encoded value will change. I want to avoid that.

Abhishek
  • 6,912
  • 14
  • 59
  • 85
  • http://stackoverflow.com/a/4515863/669721 – Miroshko May 04 '15 at 12:51
  • 2
    fwiw, in json, the keys are unordered. So, building something else that relies on any particular ordering is a questionable idea... unless you want this just for aesthetics. – FatalError May 04 '15 at 12:51
  • @FatalError I want them to be in order because I'll be encoding of the json string. If keys moved around, my encoding will change and I don't want to do that. Edited in question as well. So, I would need it to be sorted. – Abhishek May 04 '15 at 12:53
  • @Miroshko link doesn't address my problem completely. Here the problem is class structure can change. – Abhishek May 04 '15 at 12:54
  • @Abhishek: Imo you'd be better served to deserialize the json and then hash the resulting object in some normalized way where you have control over exactly what you're hashing. The same object could be serialized many equivalent ways into a JSON object -- even if the fields are in the same order, it could have extra whitespace (e.g. pretty printed) etc. – FatalError May 04 '15 at 14:14
  • @FatalError I'm not doing pretty printed or any other formatting stuff. So, I don't think that would be an issue here. – Abhishek May 04 '15 at 14:35
  • Possible duplicate of [How to sort GSON Array based on a key?](https://stackoverflow.com/questions/18575757/how-to-sort-gson-array-based-on-a-key) – Zon Jun 25 '18 at 09:22

3 Answers3

13

First of all, the keys of a json object are unordered by definition, see http://json.org/.

If you merely want a json string with ordered keys, you can try deserializing your json into a sorted map, and then serialize the map in order to get the sorted-by-key json string.

GsonTest obj=new GsonTest();
DataObject obj2 = new DataObject();
Gson gson = new Gson();

String json = gson.toJson(obj2);
TreeMap<String, Object> map = gson.fromJson(json, TreeMap.class);
String sortedJson = gson.toJson(map);
wings
  • 791
  • 6
  • 21
  • 2
    This partially answers my question. Why partially? It is because when I tried nested json, it didn't gave me expected output in nested structure. – Abhishek May 04 '15 at 13:13
  • @Abhishek Well, if you want to sort nested structure as well, maybe json object(map) is not the perfect choice of representation, as already discussed in http://stackoverflow.com/questions/4515676/keep-the-order-of-the-json-keys-during-json-conversion-to-csv/4515863#4515863 – wings May 05 '15 at 07:33
  • @Abhishek However, if you could show me a simple use case, maybe I'm able to help you. – wings May 05 '15 at 07:39
  • 2
    simple use case if that I need to calculate difference of huge json files. The keys needn't follow same order in both jsons, that is the issue. I thought of comparing encoded values instead of comparing json string. – Abhishek May 05 '15 at 08:17
  • 1
    Beware that this trick will also rewrite your numbers into double, for example `{ "key":1 }` gets rewritten as `{ "key":1.0 }`. – GaspardP Aug 07 '19 at 05:04
3

Like others have mentioned that by design JSON is not supposed to have sorted keys in itself. You can also come up with a recursive solution to do it. I won't say my solution is very efficient but it does the intended job. Please have a look at the following piece of code.

private static JsonObject sortAndGet(JsonObject jsonObject) {
    List<String> keySet = jsonObject.keySet().stream().sorted().collect(Collectors.toList());
    JsonObject temp = new JsonObject();
    for (String key : keySet) {
        JsonElement ele = jsonObject.get(key);
        if (ele.isJsonObject()) {
            ele = sortAndGet(ele.getAsJsonObject());
            temp.add(key, ele);
        } else if (ele.isJsonArray()) {
            temp.add(key, ele.getAsJsonArray());
        } else
            temp.add(key, ele.getAsJsonPrimitive());
    }
    return temp;
}

Input:

{"c":"dhoni","a":"mahendra","b":"singh","d":{"c":"tendulkar","b":"ramesh","a":"sachin"}}

Output:

{"a":"mahendra","b":"singh","c":"dhoni","d":{"a":"sachin","b":"ramesh","c":"tendulkar"}}
Utsav Sinha
  • 605
  • 1
  • 5
  • 12
-1

Perhaps a work around is for your class wrap a TreeMap which maintains sort order of the keys. You can add getters and setters for convenience. When you gson the TreeMap, you'll get ordered keys.