Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to maintain JSON's order in Groovy's JsonSlurper?

Tags:

java

json

groovy

I am reading a simple JSON....

{"A":0,"B":0,"C":2,"D":0,"F":5}

into a map using JsonSlurper in Groovy...

Map gradeDistributon = jsonSlurper.parseText(jsonString)

But when iterating over this map with a closure..

gradeDistributon.each{ entry ->   
     println "From map got key ${entry.key}"

I am seeing the keys are not in the order they were in the original JSON, for example 'C' comes first. I think this is because Map does not maintain insertion order in Java. Is there a way I can keep the order of the original JSON?

If it means reading the JSON in a different way (instead of into a Map with JsonSlurper) then I am fine with that if you can show me how.

like image 340
AbuMariam Avatar asked Oct 19 '22 00:10

AbuMariam


1 Answers

You can set JVM system property jdk.map.althashing.threshold to make JsonSlurper to use a LinkedHashMap instead of TreeMap as the internal Map implementation, e.g. -Djdk.map.althashing.threshold=512.

The reason is in source code of groovy.json.internal.LazyMap used by JsonSlurper.

private static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");

private void buildIfNeeded() {  
    if (map == null) {
        /** added to avoid hash collision attack. */
        if (Sys.is1_7OrLater() && JDK_MAP_ALTHASHING_SYSPROP != null) {
            map = new LinkedHashMap<String, Object>(size, 0.01f);
        } else {
            map = new TreeMap<String, Object>();
        }
    }
}

Please note this solution should be used as a hack as it depends on Groovy's internal implementation details. So this behavior may change in future version of Groovy.

See my blog post for details.

like image 133
Alex Cheng Avatar answered Nov 01 '22 13:11

Alex Cheng