Parece Gson.toJson(Object objeto) genera código JSON con aleatoriamente propagación de los campos del objeto. Hay manera de arreglar el orden de los campos, de alguna manera?


    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)

Gracias.

  • ¿Por qué es una secuencia pertinente? Esto indica un mal herramienta para analizar el JSON.
  • También me preguntaba por qué. Pero el servidor es un .NETO de la aplicación. Los autores de la aplicación dicen que necesitan el campo denominado «__type» (señala el esquema) para ser el primero entre otros.
  • Wow. De todos modos, esto es posible con un serializador personalizado. He publicado una respuesta.
  • Me gustaría petición de la .NETO de la aplicación de los autores para descartar este requisito y aplicar más robusto JSON de procesamiento.
  • Si tienes la oportunidad, también se puede golpear el .NETO de la aplicación de los autores con el JSON especificaciones, lo que, respecto de lo que un objeto JSON es, claramente dice: «Un objeto es una colección desordenada de cero o más pares de nombre/valor…» [ietf.org/rfc/rfc4627.txt?number=4627] por Lo tanto, su aplicación de mensajería/API no es JSON especificación compatible. (Argumentos como este tienden a funcionar especialmente bien con los de fantasía «enterprise architect» a la gente.)
  • Yo quería un diferente orden de los campos en mi JSON, así que he cambiado el orden de los campos en mi código fuente y se hizo el truco para mí. Tal vez, esto puede ayudar a otros también. (GSON 2.6.2)
  • Tal vez si usted desea metadatos en el principio usted desea esto.

4 Comentarios

  1. 20

    Si GSON no admite la definición de la orden de los campos, hay otras bibliotecas que hacer. Jackson permite definining esta con @JsonPropertyOrder, por ejemplo. Tener que especificar el propio personalizado serializador parece muchisimo trabajo para mí.

    Y sí, estoy de acuerdo en que como por JSON especificación, aplicación no debe esperar específicos de la orden de los campos.

    • Eso es lo que yo necesitaba. Debería funcionar de la mejor en este caso (es decir, la serialización de objetos simples con forzando a una propiedad para ser la primera .NET analizador en el otro lado). Gracias @StaxMan.
    • Estoy serializar algunos de los Frijoles a JSON utilizando Jackson para la persistencia y pruebas. Cambios en el formato de hecho es difícil escribir afirmaciones en contra de la cadena serializada. Esta fue sólo la medicina para hacer mis pruebas de trabajo =)
    • Me gustaría mucho mejores como la anotación de enfoque… google es dormir !!!
    • nunca se debe comparar salida JSON a una rígida Cadena, que es simplemente buscar problemas. Además de ordenar que se pueden cambiar los aspectos de espacio en blanco o escape puede cambiar, legalmente, y sin cambiar la lógica del contenido. Por lo tanto la comparación debe hacer cumplir canonicality de algún tipo (no hay una norma especifica para JSON (que yo sepa), o se debe utilizar un objeto JSON modelo (mejor opción). Jackson ha JsonNode, y su equals() funciona bien para las pruebas, por ejemplo; ignora el pedido de propiedades, valores están unificados.
    • Aunque estoy de acuerdo con su declaración para el código de producción, por unidad de pruebas (y ciertas pruebas de integración) considero que es una manera sencilla de escribir afirmaciones.
    • Ok sí, para pruebas sencillas que puede ser suficiente. Es bueno ser conscientes de los problemas con cosas como el pedido, pero al menos con las pruebas de uno puede tener el control total sobre la entrada para evitar más problemas.

  2. 28

    Que había necesidad de crear una personalizada JSON serializador.

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

    y utilizarlo como sigue:

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

    De esta forma se mantiene el orden como se ha especificado en el serializador.

    Véase también:

    • Que este enfoque funciona lamentablemente no está en la documentación de la JsonObject.add(String, JsonElement) método (o en la documentación para el addProperty métodos), sino que es revelado en la documentación de la entrySet() método! (Para los interesados: La implementación subyacente que proporciona para esta función almacena los elementos que se añaden mediante un LinkedHashMap.)
    • gracias. Sin embargo, en mi caso la solución es demasiado pesado. Prefiero prefieren JsonWriter recomendada por @Programador de Bruce. Y sí, qué vergüenza .NET json parser.
    • Demasiado pesado? Tal vez usted está haciendo algo para lo cual no hay una manera más fácil de hacerlo. Prefiero usar un custom deserializer sobre el uso de la JsonWriter directamente en casi cualquier situación. Para el problema específico que se describe, me gustaría tener BalusC la solución de un par de pasos más allá, para hacerlo más genérico y para hacer que el elemento de orden externamente configurable. A continuación, podría ser reutilizados por diferentes objetos.
    • Eso es una gran solución. Yo quería algo así y esta solución realmente me ayudó. Gracias Compañero 🙂
    • Gran respuesta. +1 se puede registrar varios adaptadores en el GsonBuilder dependiendo del objeto de la composición. GsonBuilder gson = new GsonBuilder(); gson.registerTypeAdapter(MyType2.class, new MyTypeAdapter()); gson.registerTypeAdapter(MyType.class, new MySerializer()); gson.registerTypeAdapter(MyType.class, new MyDeserializer()); gson.registerTypeAdapter(MyType.class, new MyInstanceCreator());
    • Esta es la única respuesta correcta!

  3. 2

    Aquí está mi solución para el traspaso de más de json archivos de texto en un directorio determinado y escrito sobre la parte superior de ellos con ordenada versiones:

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

    Es bastante chapucero porque depende del hecho de que Gson utiliza LinkedTreeMap cuando el Tipo es simplemente Objeto. Esta es una implementación detalles que probablemente no está garantizada. De todos modos, es lo suficientemente bueno para mi corta duración a los efectos de…

    • Funciona realmente bien! Mientras Gson utiliza internamente LinkedTreeMap que esto iba a funcionar bien.
  4. 2

    Realidad Gson.toJson(Object objeto) no genera campos en orden aleatorio. El orden de resultado json depende literal de la secuencia de los campos de nombres.

    Yo tenía el mismo problema y fue resuelto por el literal orden de las propiedades de los nombres de la clase.

    El ejemplo en la pregunta siempre devolverá el siguiente jsonRequest:

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

    Con el fin de tener un orden específico debe modificar los campos de nombres, por ejemplo: si desea baz a ser el primero en orden luego viene 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 será { "f1_baz ":"baz", "f2_bar":"bar" }

    • atención a elaborar?
    • la respuesta ha sido modificado
    • Gracias, upvoted para tomar el esfuerzo de mejorar. Por CIERTO, me pregunto si el SerializedName la anotación de los nombres de alterar ese orden.

Dejar respuesta

Please enter your comment!
Please enter your name here