java - example - La mejor manera de usar Jackson JsonNodeFactory
java jackson readtree (4)
Esto funciona, aunque la intención es que es la fábrica la que crea instancias. Pero lo más común es que solo accedas a todo usando ObjectMapper, como:
ObjectMapper mapper = new ObjectMapper();
ObjectNode dataTable = mapper.createObjectNode();
ArrayNode aa = dataTable.putArray("aaData");
La razón principal para que JsonNodeFactory se separe es permitirle crear tipos de nodos personalizados (generalmente subclases de instancias estándar); y luego configure ObjectMapper para usar diferentes fábricas. Por conveniencia, ArrayNode y ObjectNode tienen referencias a una instancia de fábrica, que se usa con "putArray" y otros métodos que necesitan crear nuevos nodos.
Estoy usando Jackson para construir un objeto JSON personalizado. ¿Es la forma correcta de hacer esto?
Parece funcionar bien (y la salida es correcta) pero puede que falte la forma en que uso JsonNodeFactory. ¿El objeto está destinado a ser pasado como lo he hecho 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);
Si hace un montón de código JsonNode
en código, puede que le interese el siguiente conjunto de utilidades. La ventaja de usarlos es que admiten un estilo de encadenamiento más natural que muestra mejor la estructura del JSON bajo construcción.
Aquí hay 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 al siguiente JSON:
{"x":"1", "y": [{"z": "2"}]}
Aquí están 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 implementación utiliza Lombok , pero puede desugarlo fácilmente para completar el texto de Java.
Solo una sugerencia, sería más fácil tratar directamente con tipos de datos simples y serializarlos a JSON y volver a usar Jackson ObjectMapper, en lugar de tratar con Jackson Treemodel sin procesar
Entonces, en tu ejemplo, podrías crear una estructura del siguiente tipo:
class AaData{
private List<ARow> rowList = new ArrayList<ARow>();
..
class ARow{
String ounces;
String revolutions;
..
Entonces lo siguiente generará el json apropiado para ti:
StringWriter sw = new StringWriter();
JsonFactory jf = new JsonFactory();
ObjectMapper m = new ObjectMapper();
m.writeValue(sw, aaData);
System.out.println(sw.toString());
ObjectNode factory = JsonNodeFactory.instance.objectNode();
Esto funciona bien Creo que esta es una manera más fácil.