2011-06-10 29 views
23

Estoy usando Jackson para crear un objeto JSON personalizado. ¿Es la forma correcta de hacer esto?La mejor manera de usar Jackson JsonNodeFactory

Parece que funciona bien (y la salida es correcta) pero me puede faltar la forma en que uso JsonNodeFactory. ¿El objeto debe ser pasado como lo hice aquí?

JsonNodeFactory factory = JsonNodeFactory.instance; 

     ObjectNode dataTable = new ObjectNode(factory); 

     ArrayNode aaData = new ArrayNode(factory); 

     for (PkgLoad pkgLoad : pkgLoadList) { 
      ObjectNode row = new ObjectNode(factory); 
      row.put("ounces", pkgLoad.ounces); 
      row.put("revolutions", pkgLoad.revolutions); 

      aaData.add(row); 
     } 

     dataTable.put("aaData", aaData); 

Respuesta

36

Esto funciona, aunque la intención es que sea la fábrica la que cree instancias. Pero con mayor frecuencia que acaba de acceder a todas usando ObjectMapper, como:

ObjectMapper mapper = new ObjectMapper(); 
ObjectNode dataTable = mapper.createObjectNode(); 
ArrayNode aa = dataTable.putArray("aaData"); 

La razón principal de por separado JsonNodeFactory es que permitirá crear tipos de nodos personalizados (generalmente subclases de casos estándar); y luego configure ObjectMapper para usar fábrica diferente. Para mayor comodidad, ArrayNode y ObjectNode sí tienen referencia a una instancia de fábrica, que se usa con "putArray" y otros métodos que necesitan crear nuevos nodos.

3

Sólo una sugerencia, sería más fácil de tratar directamente con los tipos de datos simples y serializar los a JSON y viceversa usando Jackson ObjectMapper, en lugar de lidiar con prima Jackson Treemodel

Así que en su ejemplo, se podría crear una estructura del siguiente tipo:

class AaData{ 
    private List<ARow> rowList = new ArrayList<ARow>(); 
.. 

class ARow{ 
    String ounces; 
    String revolutions; 
.. 

a continuación, el siguiente generará el JSON apropiada para usted:

StringWriter sw = new StringWriter(); 
JsonFactory jf = new JsonFactory(); 
ObjectMapper m = new ObjectMapper(); 
m.writeValue(sw, aaData); 
System.out.println(sw.toString()); 
+0

Eso sería mejor y lo he hecho en algunos casos. El problema es que, en este caso, necesito tener control sobre cada fila porque tengo instrucciones condicionales sobre qué escribir. A veces, onzas es gramos. Tengo que escribir el color de la fila en cada fila. Eso es diferente para cada fila. –

+0

@Drew H, te he visto publicar sobre este proyecto un par de veces. En general, me parece que tal vez sería más simple si realizara menos o ningún cambio en la presentación en su modelo de objeto en el momento de la deserialización, y simplemente infló el modelo de objetos del JSON en función de los datos que están presentes en el JSON, sin inyectar datos adicionales, y luego, más cerca del proyecto donde se mostrarán los datos, tienen un código relacionado con la generación de un modelo de vista (o alteración del modelo existente) para la presentación. –

+1

(continuando ...) Mi punto es que, si es posible mantener el enlace de datos entre JSON y las estructuras de datos de Java simple, entonces manténgalo simple. Es fantástico cuando la deserialización toma solo dos o tres líneas de código, lo cual es completamente posible y muy común cuando se usan API como Gson o Jackson. Para mí, es una razón importante para usar estas API. –

2

Si hace un montón de JsonNode construyendo en código, puede ser interesante en el siguiente conjunto de utilidades. El beneficio de usarlos es que admiten un estilo de encadenamiento más natural que muestra mejor la estructura del JSON en construcción.

Aquí es un ejemplo de uso:

import static JsonNodeBuilders.array; 
import static JsonNodeBuilders.object; 

... 

val request = object("x", "1").with("y", array(object("z", "2"))).end(); 

que es equivalente a la siguiente JSON:

{"x":"1", "y": [{"z": "2"}]} 

Estas son las clases:

import static lombok.AccessLevel.PRIVATE; 

import com.fasterxml.jackson.databind.JsonNode; 
import com.fasterxml.jackson.databind.node.ArrayNode; 
import com.fasterxml.jackson.databind.node.JsonNodeFactory; 
import com.fasterxml.jackson.databind.node.ObjectNode; 

import lombok.NoArgsConstructor; 
import lombok.NonNull; 
import lombok.RequiredArgsConstructor; 
import lombok.val; 

/** 
* Convenience {@link JsonNode} builder. 
*/ 
@NoArgsConstructor(access = PRIVATE) 
public final class JsonNodeBuilders { 

    /** 
    * Factory methods for an {@link ObjectNode} builder. 
    */ 

    public static ObjectNodeBuilder object() { 
    return object(JsonNodeFactory.instance); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, boolean v1) { 
    return object().with(k1, v1); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, int v1) { 
    return object().with(k1, v1); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, float v1) { 
    return object().with(k1, v1); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, String v1) { 
    return object().with(k1, v1); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, String v1, @NonNull String k2, String v2) { 
    return object(k1, v1).with(k2, v2); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, String v1, @NonNull String k2, String v2, 
     @NonNull String k3, String v3) { 
    return object(k1, v1, k2, v2).with(k3, v3); 
    } 

    public static ObjectNodeBuilder object(@NonNull String k1, JsonNodeBuilder<?> builder) { 
    return object().with(k1, builder); 
    } 

    public static ObjectNodeBuilder object(JsonNodeFactory factory) { 
    return new ObjectNodeBuilder(factory); 
    } 

    /** 
    * Factory methods for an {@link ArrayNode} builder. 
    */ 

    public static ArrayNodeBuilder array() { 
    return array(JsonNodeFactory.instance); 
    } 

    public static ArrayNodeBuilder array(@NonNull boolean... values) { 
    return array().with(values); 
    } 

    public static ArrayNodeBuilder array(@NonNull int... values) { 
    return array().with(values); 
    } 

    public static ArrayNodeBuilder array(@NonNull String... values) { 
    return array().with(values); 
    } 

    public static ArrayNodeBuilder array(@NonNull JsonNodeBuilder<?>... builders) { 
    return array().with(builders); 
    } 

    public static ArrayNodeBuilder array(JsonNodeFactory factory) { 
    return new ArrayNodeBuilder(factory); 
    } 

    public interface JsonNodeBuilder<T extends JsonNode> { 

    /** 
    * Construct and return the {@link JsonNode} instance. 
    */ 
    T end(); 

    } 

    @RequiredArgsConstructor 
    private static abstract class AbstractNodeBuilder<T extends JsonNode> implements JsonNodeBuilder<T> { 

    /** 
    * The source of values. 
    */ 
    @NonNull 
    protected final JsonNodeFactory factory; 

    /** 
    * The value under construction. 
    */ 
    @NonNull 
    protected final T node; 

    /** 
    * Returns a valid JSON string, so long as {@code POJONode}s not used. 
    */ 
    @Override 
    public String toString() { 
     return node.toString(); 
    } 

    } 

    public final static class ObjectNodeBuilder extends AbstractNodeBuilder<ObjectNode> { 

    private ObjectNodeBuilder(JsonNodeFactory factory) { 
     super(factory, factory.objectNode()); 
    } 

    public ObjectNodeBuilder withNull(@NonNull String field) { 
     return with(field, factory.nullNode()); 
    } 

    public ObjectNodeBuilder with(@NonNull String field, int value) { 
     return with(field, factory.numberNode(value)); 
    } 

    public ObjectNodeBuilder with(@NonNull String field, float value) { 
     return with(field, factory.numberNode(value)); 
    } 

    public ObjectNodeBuilder with(@NonNull String field, boolean value) { 
     return with(field, factory.booleanNode(value)); 
    } 

    public ObjectNodeBuilder with(@NonNull String field, String value) { 
     return with(field, factory.textNode(value)); 
    } 

    public ObjectNodeBuilder with(@NonNull String field, JsonNode value) { 
     node.set(field, value); 
     return this; 
    } 

    public ObjectNodeBuilder with(@NonNull String field, @NonNull JsonNodeBuilder<?> builder) { 
     return with(field, builder.end()); 
    } 

    public ObjectNodeBuilder withPOJO(@NonNull String field, @NonNull Object pojo) { 
     return with(field, factory.pojoNode(pojo)); 
    } 

    @Override 
    public ObjectNode end() { 
     return node; 
    } 

    } 

    public final static class ArrayNodeBuilder extends AbstractNodeBuilder<ArrayNode> { 

    private ArrayNodeBuilder(JsonNodeFactory factory) { 
     super(factory, factory.arrayNode()); 
    } 

    public ArrayNodeBuilder with(boolean value) { 
     node.add(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(@NonNull boolean... values) { 
     for (val value : values) 
     with(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(int value) { 
     node.add(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(@NonNull int... values) { 
     for (val value : values) 
     with(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(float value) { 
     node.add(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(String value) { 
     node.add(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(@NonNull String... values) { 
     for (val value : values) 
     with(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(@NonNull Iterable<String> values) { 
     for (val value : values) 
     with(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(JsonNode value) { 
     node.add(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(@NonNull JsonNode... values) { 
     for (val value : values) 
     with(value); 
     return this; 
    } 

    public ArrayNodeBuilder with(JsonNodeBuilder<?> value) { 
     return with(value.end()); 
    } 

    public ArrayNodeBuilder with(@NonNull JsonNodeBuilder<?>... builders) { 
     for (val builder : builders) 
     with(builder); 
     return this; 
    } 

    @Override 
    public ArrayNode end() { 
     return node; 
    } 

    } 

} 

Tenga en cuenta que la aplicación utiliza Lombok , pero puede desaguarlo fácilmente para completar el texto estándar de Java.

0
ObjectNode factory = JsonNodeFactory.instance.objectNode(); 

Esto funciona bien. Creo que esta es una forma más fácil.

Cuestiones relacionadas