【问题标题】:How to create json, sorted on keys, using gson?如何使用gson创建json,按键排序?
【发布时间】:2015-07-13 20:47:53
【问题描述】:

我需要创建常量 json 字符串或按键排序的 json。常量 json 字符串是什么意思?请查看我创建的以下代码示例。

我的代码 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);
    }
}

输出 1:

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

我的代码 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);
    }
}

输出 2:

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

如果您看到,如果我切换变量(DataObject 类中的data1data2),我会得到不同的 json。我的目标是获得相同的 json,即使有人更改了类变量的位置。当有人添加新变量时,我明白了,json 会改变。但是当变量移动时 json 不应该改变。所以,我的目标是获得标准的 json,可能按同一类的排序键顺序。如果有嵌套的json,那么应该在嵌套结构中排序。

两个代码运行时的预期输出

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

我明白了,我需要更改String json = gson.toJson(obj2); 行中的一些内容,但我该怎么办?

为什么我需要订购它们?

我需要对 json 字符串进行编码,然后将其传递给另一个函数。如果我更改键的顺序,即使值保持不变,编码的值也会改变。我想避免这种情况。

【问题讨论】:

  • fwiw,在 json 中,键是无序的。因此,构建依赖于任何特定顺序的其他东西是一个值得商榷的想法……除非你只是为了美观而想要这样做。
  • @FatalError 我希望它们按顺序排列,因为我将对 json 字符串进行编码。如果键移动,我的编码会改变,我不想这样做。也进行了有问题的编辑。所以,我需要对它进行排序。
  • @Miroshko 链接不能完全解决我的问题。这里的问题是类结构可以改变。
  • @Abhishek:Imo 你最好反序列化 json,然后以某种规范化的方式对生成的对象进行哈希处理,这样你就可以控制你正在哈希的内容。同一个对象可以以多种等效方式序列化为 JSON 对象——即使字段顺序相同,它也可能有额外的空格(例如漂亮的打印)等。

标签: java json gson


【解决方案1】:

首先,根据定义,json 对象的键是无序的,参见http://json.org/

如果您只想要一个带有有序键的 json 字符串,您可以尝试将您的 json 反序列化为一个排序的映射,然后序列化映射以获得按键排序的 json 字符串。

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

【讨论】:

  • 这部分回答了我的问题。为什么是部分?这是因为当我尝试嵌套 json 时,它没有在嵌套结构中给我预期的输出。
  • @Abhishek 好吧,如果你也想对嵌套结构进行排序,也许 json object(map) 不是完美的表示选择,正如stackoverflow.com/questions/4515676/…中已经讨论过的@
  • @Abhishek 但是,如果你能给我看一个简单的用例,也许我能帮你。
  • 简单的用例,如果我需要计算巨大的 json 文件的差异。两个 json 中的键不必遵循相同的顺序,这就是问题所在。我想到了比较编码值而不是比较 json 字符串。
  • 请注意,此技巧还会将您的数字重写为双精度数,例如 { "key":1 } 会被重写为 { "key":1.0 }
【解决方案2】:

也许解决方法是为您的类包装一个维护键排序顺序的 TreeMap。为方便起见,您可以添加 getter 和 setter。当您使用 TreeMap 时,您将获得有序的键。

【讨论】:

    【解决方案3】:

    就像其他人提到的那样,按照设计,JSON 本身不应该有排序的键。你也可以想出一个递归的解决方案来做到这一点。我不会说我的解决方案非常有效,但它完成了预期的工作。请看下面这段代码。

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

    输入:

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

    输出:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-06-19
      • 1970-01-01
      • 2014-05-14
      • 2023-03-16
      相关资源
      最近更新 更多