如何在Groovy的JsonSlurper中维护JSON的顺序?

时间:2015-10-08 14:09:31

标签: java json groovy

我正在阅读一个简单的JSON ....

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

在Groovy中使用JsonSlurper进入地图...

Map gradeDistributon = jsonSlurper.parseText(jsonString)

但是当用一个闭包迭代这个地图时..

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

我看到键不符合原始JSON中的顺序,例如'C'首先出现。我认为这是因为Map不能在Java中维护插入顺序。有没有办法保持原始JSON的顺序?

如果这意味着以不同的方式阅读JSON(而不是使用JsonSlurper进入Map),那么如果你能告诉我如何,我就可以了。

3 个答案:

答案 0 :(得分:2)

您可以设置JVM系统属性jdk.map.althashing.threshold,使JsonSlurper使用LinkedHashMap代替TreeMap作为内部Map实施,例如-Djdk.map.althashing.threshold=512

原因是groovy.json.internal.LazyMap使用的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>(); } } }

DoesNotExist at /admin/login/
Site matching query does not exist.

请注意,此解决方案应该用作hack,因为它取决于Groovy的内部实现细节。所以这种行为可能会在未来的Groovy版本中发生变化。

有关详细信息,请参阅我的source code

答案 1 :(得分:1)

我无法使用groovy 2.4.5重现您的行为,但您可以尝试使用LinkedHashMap(允许迭代映射键,保持插入条目的顺序):

import groovy.json.*

def jsonText = '''
{"A":0,"B":0,"C":2,"D":0,"F":5,"G":7,"H":9}
'''

LinkedHashMap json = new JsonSlurper().parseText(jsonText)
json.each{ entry ->
  println "${entry.key}"
}

注意:如@XenoN所述,JsonSlurper()在解析过程中对json键进行排序,因此独立于输入顺序(即。{"H":0,"B":0,"A":2,"D":0,"G":5,"F":7,"C":9}),JsonSlurper的输出将是总是:{"A":2,"B":0,"C":9,"D":0,"F":7,"G":5,"H":0}

使用 LinkedHashMap 而不是HashMap,我们保留了JsonSlurper给出的顺序。

答案 2 :(得分:0)

所以这只是在JsonSlurper构建Map之后对键进行排序的问题,因为我只是读入了一个TreeMap,它默认对键进行排序。

TreeMap gradeDistributon = jsonSlurper.parseText(jsonString)