13

I had a need for having Key/Value pairs in the order of my insertion, so I opted to use LinkedHashMap over HashMap. But I need to convert the LinkedHashMap into a JSON String where the order in the LinkedHashMap is maintained in the string.

But currently I'm achieving it by:

  1. First converting the LinkedHashMap into JSON.
  2. Then converting the JSON into a string.

    import java.util.LinkedHashMap;
    import java.util.Map;
    
    import org.json.JSONObject;
    
    public class cdf {
        public static void main(String[] args) {
            Map<String,String > myLinkedHashMap =  new LinkedHashMap<String, String>();
            myLinkedHashMap.put("1","first");
            myLinkedHashMap.put("2","second");
            myLinkedHashMap.put("3","third");
    
            JSONObject json = new JSONObject(myLinkedHashMap);
            System.out.println(json.toString());
        }
    }
    

The output is:

{"3":"third","2":"second","1":"first"} . 

But I want it in the order of insertion of the keys, like this:

{"1":"first","2":"second","3":"third"}

Once I convert the LinkedHashMap into a JSON it loses it order (it's obvious that JSON doesn't have the notion of order) and hence the string too is out of order. Now, how do I generate a JSON string whose order is same as the LinkedHashMap?

11
  • 1
    It would really help if you'd show us this in a short but complete program demonstrating the problem... (Code, expected output, actual output.) Commented Apr 7, 2015 at 12:13
  • You can add an element order to each JSON object so you are able to track the string ordering after receiving and parsing the JSON. Commented Apr 7, 2015 at 12:13
  • @JonSkeet: I have edited the question now ..Hope this is clear enough . Commented Apr 7, 2015 at 12:23
  • Hmm. The output on my machine is just {} - but then it didn't compile to start with anyway. Please update the question with actual code you've compiled and run... Commented Apr 7, 2015 at 12:26
  • @MrPolywhirl: I've rolled back to revision 4 as although the text may not be as good, it at least includes a (flawed) example... Commented Apr 7, 2015 at 12:27

7 Answers 7

18

Gson if your friend. This will print the ordered map into an ordered JSON string.

If you want to preserve insertion order, use a LinkedHashMap.

I used the latest version of Gson (2.8.5), you can can download it via the following options at the bottom of this post.

import java.util.*;
import com.google.gson.Gson;

public class OrderedJson {
    public static void main(String[] args) {
        // Create a new ordered map.
        Map<String,String> myLinkedHashMap = new LinkedHashMap<String, String>();

        // Add items, in-order, to the map.
        myLinkedHashMap.put("1", "first");
        myLinkedHashMap.put("2", "second");
        myLinkedHashMap.put("3", "third");

        // Instantiate a new Gson instance.
        Gson gson = new Gson();

        // Convert the ordered map into an ordered string.
        String json = gson.toJson(myLinkedHashMap, LinkedHashMap.class);

        // Print ordered string.
        System.out.println(json); // {"1":"first","2":"second","3":"third"}
    }
}

If you want the items to always be inserted at the right place, use a TreeMap instead.

import java.util.*;
import com.google.gson.Gson;

public class OrderedJson {
    public static void main(String[] args) {
        // Create a new ordered map.
        Map<String,String> myTreeHashMap = new TreeMap<String, String>();

        // Add items, in any order, to the map.
        myTreeHashMap.put("3", "third");
        myTreeHashMap.put("1", "first");
        myTreeHashMap.put("2", "second");

        // Instantiate a new Gson instance.
        Gson gson = new Gson();

        // Convert the ordered map into an ordered string.
        String json = gson.toJson(myTreeHashMap, TreeMap.class);

        // Print ordered string.
        System.out.println(json); // {"1":"first","2":"second","3":"third"}
    }
}

Dependency Options

Maven

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

Gradle

compile 'com.google.code.gson:gson:2.8.5'

Or you can visit Maven Central for more download options.

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks a lot :) It works :) Thank you for the Maven Dependency too , It helped :)
very useful . . . :)
It's incredible lame that Jackson can't do this.
@goat Jackson does it just fine, see my answer. OP just complicated code unnecessarily... something GSON example above also rectified.
This example doesn't work because GSON uses a TreeMap, so the right example would be to do myLinkedHashMap.put("3", "third"); and myLinkedHashMap.put("1", "one"), so you would see that GSON flips the results..
|
6

JSONObject implies use of org.json library. Don't do that; it is old prototype and there are better options like Jackson and GSON. With Jackson you would just use:

String json = new ObjectMapper().writeValueAsString(myLinkedHashMap);

and get JSON string with entries in whatever traversal order your Map uses.

Comments

1

JSON not taking insertion order due to linkedhashmap params both are string. Is it fine to change first param as Integer like below mentioned code:

Map<Integer,String > myLinkedHashMap =  new LinkedHashMap<>();
            myLinkedHashMap.put(1,"first");
            myLinkedHashMap.put(2,"second");
            myLinkedHashMap.put(3,"third");

            System.out.println(myLinkedHashMap);
            JSONObject json = new JSONObject(myLinkedHashMap);
            System.out.println(json.toString());

6 Comments

But how to convert into a one JSON string with the order maintained?
My suggested code is ordered maintained. Not able to understanding your question.
No, this won't do it - the problem is that JSONObject uses a plain HashMap behind the scenes, and you can't change that :(
@Jon Skeet - What is the wrong in this? is this output wrong? am getting output for above program: {1=first, 2=second, 3=third} {"1":"first","2":"second","3":"third"}
@Subbu: That's coincidence rather than a guarantee, I suspect. (You're still relying on the ordering of a HashMap, which is a really bad idea.)
|
0

To sort alphabetically, here is the proper way with Jackson 2.*:

Map<String, String> myLinkedHashMap = new LinkedHashMap<String, String>();
myLinkedHashMap.put("1", "first");
myLinkedHashMap.put("2", "second");
myLinkedHashMap.put("3", "third");

ObjectMapper mapper = new ObjectMapper();
mapper.configure(MapperFeature.SORT_PROPERTIES_ALPHABETICALLY, true);

try {
    System.out.println(mapper.writeValueAsString(myLinkedHashMap));
    //prints {"1":"first","2":"second","3":"third"}
} catch (JsonProcessingException e) {
    e.printStackTrace();
}

1 Comment

Alternatively for sorting one can use TreeMap as well. Serializer uses traversal order of the Map. I am not quite sure why answers claim Jackson does not preserve ordering: it does.
0

I ran into the same problem. I had to use this particular library, and the first element must be with the key "$type". Here is my decision:

import org.json.JSONObject;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;


class TypedJSONObject extends JSONObject {

    private static final String KEY = "$type";

    @Override
    public Set<Map.Entry<String, Object>> entrySet() {
        Set<Map.Entry<String, Object>> superSet = super.entrySet();
        Set<Map.Entry<String, Object>> returnSet = new LinkedHashSet<>();

        HashMap<String, Object> map = new HashMap<>();
        for (Map.Entry<String, Object> entry : superSet) {
            if (entry.getKey().equals(KEY)) {
                map.put(KEY, entry.getValue());
                break;
            }
        }
        Set<Map.Entry<String, Object>> entries = map.entrySet();

        returnSet.addAll(entries);
        returnSet.addAll(superSet);

        return returnSet;
    }
}

As you see I overrite method entrySet, that used in method toString

Comments

0

i created a hacky solution, which should not be used for production, i just use it to manualy generate json files

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

import org.json.JSONObject;

public class SortedJSONObject extends JSONObject {

    public SortedJSONObject() {
        super();
        try {
            Field mapField = JSONObject.class.getDeclaredField("map");
            mapField.setAccessible(true);
            mapField.set(this, new LinkedHashMap());
            mapField.setAccessible(false);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

}

Comments

-1

Create JsonArray for Ordered Pair...

JSONArray orderedJson=new JSONArray();
Iterator iterator= ;
    while (iterator.hasNext()) {
        Map.Entry me = (Map.Entry)iteratornext();
        System.out.print(me.getKey() + ": ");
        System.out.println(me.getValue());
        JSONObject tmpJson=new JSONObject ();
        tmpJson.put(me.getKey(),me.getValue());//add key/value to tmpjson
        orderedJson.add(tmpJson);//add tmpjson to orderedJson
    }

2 Comments

But how to convert into a one JSON string with the order maintained?
put this JSONArray into an JSONObject simply... for eg. JSONObject jObject=new JSONObject();jObject.put(orderedJson);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.