有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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

我正在读一个简单的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将其读入地图),那么如果您能告诉我如何读取,我可以接受


共 (3) 个答案

  1. # 1 楼答案

    因此,在JsonSlurper构建了地图之后,只需对键进行排序,因此我只需读入一个树映射,该树映射默认情况下会对键进行排序

    TreeMap gradeDistributon = jsonSlurper.parseText(jsonString)
    
  2. # 2 楼答案

    我无法用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给出的顺序

  3. # 3 楼答案

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

    原因在于{}使用的{}中的{a1}

    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>();
            }
        }
    }
    

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

    有关详细信息,请参见我的blog post