web-dev-qa-db-fra.com

Comment conserver la séquence des champs dans la sérialisation Gson

On dirait que Gson.toJson (objet Object) génère du code JSON avec des champs répartis de manière aléatoire de l'objet. Existe-t-il un moyen de corriger l'ordre des champs d'une manière ou d'une autre?


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

    // jsonRequest now can be { "bar":"bar", "baz":"baz" } (which is correct)
    //             and can be { "baz":"baz", "bar":"bar" } (which is a wrong sequence)

Merci.

38
Sergey Romanovsky

Si GSON ne prend pas en charge la définition de l'ordre des champs, d'autres bibliothèques le font. Jackson permet de définir cela avec @JsonPropertyOrder, par exemple. Devoir spécifier son propre sérialiseur personnalisé me semble énormément de travail.

Et oui, je suis d'accord que selon la spécification JSON, l'application ne doit pas s'attendre à un ordre spécifique des champs.

22
StaxMan

Vous devez créer un sérialiseur JSON personnalisé.

Par exemple.

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

}

et utilisez-le comme suit:

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

Cela maintient l'ordre comme vous l'avez spécifié dans le sérialiseur.

Voir également:

30
BalusC

En fait, Gson.toJson (objet Object) ne génère pas de champs dans un ordre aléatoire. L'ordre des json résultants dépend de la séquence littérale des noms des champs.

J'ai eu le même problème et il a été résolu par l'ordre littéral des noms des propriétés dans la classe.

L'exemple de la question renvoie toujours la jsonRequest suivante:

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

Afin d'avoir un ordre spécifique, vous devez modifier les noms des champs, par exemple: si vous voulez que baz soit le premier dans l'ordre vient alors 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 sera { "f1_baz ":"baz", "f2_bar":"bar" }

4
YouQam

Voici ma solution pour parcourir les fichiers texte json dans un répertoire donné et écrire par-dessus avec des versions triées:

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

C'est assez hacky car cela dépend du fait que Gson utilise LinkedTreeMap lorsque le Type est simplement Object. Il s'agit d'un détail d'implémentation qui n'est probablement pas garanti. Quoi qu'il en soit, c'est assez bon pour mes objectifs de courte durée ...

2
matt burns