开发者

How to keep fields sequence in Gson serialization

Seems like Gson.toJson(Object object) generates JSON code with randomly spread fields of the object. 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:

  • { "bar":"bar", "baz":"baz&qu开发者_开发技巧ot; } (correct)
  • { "baz":"baz", "bar":"bar" } (wrong sequence)


You'd need to create a custom JSON serializer.

E.g.

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:

  • Gson User Guide - Custom serializers and deserializers


If GSON doesn't support definition of field order, there are other libraries that do. Jackson allows definining this with @JsonPropertyOrder, for example. 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.


Actually Gson.toJson(Object object) doesn't generate fields in random order. The order of resulted json depends on literal sequence of the fields' names.

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:

{ "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:

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


Here's my solution for looping over json text files in a given directory and writing over the top of them with sorted versions:

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. This is an implementation details that is probably not guaranteed. Anyway, it's good enough for my short-lived purposes...

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜