简体   繁体   English

如何在 Gson 序列化中保持字段顺序

[英]How to keep fields sequence in Gson serialization

Seems like Gson.toJson(Object object) generates JSON code with randomly spread fields of the object.似乎Gson.toJson(Object object)生成具有随机分布的对象字段的 JSON 代码。 Is there way to fix fields order somehow?有没有办法以某种方式修复字段顺序?

public class Foo {
    public String bar;
    public String baz;
    public Foo( String bar, String baz ) {
        this.bar = bar;
        this.baz = baz;
    }
}
Gson gson = new Gson();
String jsonRequest = gson.toJson(new Foo("bar","baz"));

The string jsonRequest can be:字符串 jsonRequest 可以是:

  • { "bar":"bar", "baz":"baz" } (correct) { "bar":"bar", "baz":"baz" } (正确)
  • { "baz":"baz", "bar":"bar" } (wrong sequence) { "baz":"baz", "bar":"bar" } (顺序错误)

You'd need to create a custom JSON serializer.您需要创建一个自定义 JSON 序列化程序。

Eg例如

public class FooJsonSerializer implements JsonSerializer<Foo> {

    @Override
    public JsonElement serialize(Foo foo, Type type, JsonSerializationContext context) {
        JsonObject object = new JsonObject();
        object.add("bar", context.serialize(foo.getBar());
        object.add("baz", context.serialize(foo.getBaz());
        // ...
        return object;
    }

}

and use it as follows:并按如下方式使用它:

Gson gson = new GsonBuilder().registerTypeAdapter(Foo.class, new FooJsonSerializer()).create();
String json = gson.toJson(foo);
// ...

This maintains the order as you've specified in the serializer.这会保持您在序列化程序中指定的顺序。

See also:也可以看看:

If GSON doesn't support definition of field order, there are other libraries that do.如果 GSON 不支持字段顺序的定义,那么还有其他库支持。 Jackson allows definining this with @JsonPropertyOrder, for example.例如, Jackson允许使用 @JsonPropertyOrder 定义它。 Having to specify one's own custom serializer seems like awful lot of work to me.必须指定自己的自定义序列化程序对我来说似乎是一项艰巨的工作。

And yes, I agree in that as per JSON specification, application should not expect specific ordering of fields.是的,我同意根据 JSON 规范,应用程序不应期望字段的特定排序。

Actually Gson.toJson(Object object) doesn't generate fields in random order.实际上 Gson.toJson(Object object) 不会以随机顺序生成字段。 The order of resulted json depends on literal sequence of the fields' names.结果 json 的顺序取决于字段名称的字面顺序。

I had the same problem and it was solved by literal order of properties' names in the class.我遇到了同样的问题,它是通过类中属性名称的字面顺序解决的。

The example in the question will always return the following jsonRequest:问题中的示例将始终返回以下 jsonRequest:

{ "bar":"bar", "baz":"baz" }

In order to have a specific order you should modify fields' names, ex: if you want baz to be first in order then comes bar :为了有一个特定的顺序,你应该修改字段的名称,例如:如果你希望baz在第一位,那么bar

public class Foo {
    public String f1_baz;
    public String f2_bar;

    public Foo ( String f1_baz, String f2_bar ) {
        this.f1_baz = f1_baz;
        this.f2_bar = f2_bar;
    }
}

jsonRequest will be { "f1_baz ":"baz", "f2_bar":"bar" } jsonRequest 将是{ "f1_baz ":"baz", "f2_bar":"bar" }

Here's my solution for looping over json text files in a given directory and writing over the top of them with sorted versions:这是我在给定目录中循环 json 文本文件并使用排序版本覆盖它们的解决方案:

private void standardizeFormat(File dir) throws IOException {
    File[] directoryListing = dir.listFiles();
    if (directoryListing != null) {
        for (File child : directoryListing) {
            String path = child.getPath();
            JsonReader jsonReader = new JsonReader(new FileReader(path));

            Gson gson = new GsonBuilder().setPrettyPrinting().registerTypeAdapter(LinkedTreeMap.class, new SortedJsonSerializer()).create();
            Object data = gson.fromJson(jsonReader, Object.class);
            JsonWriter jsonWriter = new JsonWriter(new FileWriter(path));
            jsonWriter.setIndent("  ");
            gson.toJson(data, Object.class, jsonWriter);
            jsonWriter.close();
        }
    }
}

private class SortedJsonSerializer implements JsonSerializer<LinkedTreeMap> {
    @Override
    public JsonElement serialize(LinkedTreeMap foo, Type type, JsonSerializationContext context) {
        JsonObject object = new JsonObject();
        TreeSet sorted = Sets.newTreeSet(foo.keySet());
        for (Object key : sorted) {
            object.add((String) key, context.serialize(foo.get(key)));
        }
        return object;
    }
}

It's pretty hacky because it depends on the fact that Gson uses LinkedTreeMap when the Type is simply Object.这很棘手,因为它取决于当 Type 只是 Object 时 Gson 使用 LinkedTreeMap 的事实。 This is an implementation details that is probably not guaranteed.这是一个可能无法保证的实现细节。 Anyway, it's good enough for my short-lived purposes...无论如何,这对于我短暂的目的来说已经足够了......

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM