【问题标题】:Best way to use Jackson JsonNodeFactory使用杰克逊 JsonNodeFactory 的最佳方式
【发布时间】:2011-06-10 20:49:48
【问题描述】:

我正在使用 Jackson 构建自定义 JSON 对象。这是正确的做法吗?

它似乎运行良好(并且输出正确),但我可能会错过使用 JsonNodeFactory 的方式。该对象是否像我在这里所做的那样被传递?

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

【问题讨论】:

    标签: java json playframework jackson


    【解决方案1】:

    这行得通,尽管意图是它是创建实例的工厂。但大多数情况下,您只需使用 ObjectMapper 访问所有内容,例如:

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

    分离JsonNodeFactory的主要原因是允许你创建自定义节点类型(通常是标准实例的子类);然后配置 ObjectMapper 使用不同的工厂。 为方便起见,ArrayNode 和 ObjectNode 确实引用了工厂实例,它与“putArray”和其他需要创建新节点的方法一起使用。

    【讨论】:

      【解决方案2】:

      如果您在代码中构建了大量JsonNode,您可能会对以下实用程序集感兴趣。使用它们的好处是它们支持更自然的链接样式,可以更好地显示正在构建的 JSON 的结构。

      这是一个示例用法:

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

      相当于下面的 JSON:

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

      以下是课程:

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

      请注意,该实现使用Lombok,但您可以轻松地将其脱糖以填充 Java 样板。

      【讨论】:

        【解决方案3】:

        只是一个建议,直接处理简单的数据类型并将其序列化为 JSON 并使用 Jackson ObjectMapper 返回会更容易,而不是处理原始的Jackson Treemodel

        因此,在您的示例中,您可以创建以下类型的结构:

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

        那么下面会为你生成合适的json:

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

        【讨论】:

        • 这样会更好,在某些情况下我已经这样做了。问题是,在这种情况下,我需要控制每一行,因为我有关于要写什么的条件语句。有时盎司是克。我必须在每一行上写入行颜色。每一行都是不同的。
        • @Drew H,我已经看过你几次关于这个项目的帖子。总的来说,在我看来,如果您在反序列化时对对象模型进行较少或不进行基于表示的更改,并且只是根据存在于JSON,没有注入额外的数据,然后在项目中更接近要显示数据的位置,具有与生成视图模型(或更改现有模型)有关的代码以进行演示。
        • (继续...)我的观点是,如果可以保持 JSON 和 Java 数据结构之间的数据绑定简单,那么就保持简单。当反序列化只需要两三行代码时,这真是太棒了,这在使用像 Gson 或 Jackson 这样的 API 时是完全可能的并且非常常见。对我来说,这是使用这些 API 的主要原因。
        • 嗨,谢谢您的发帖。我本来就是按照你说的做的。由于 JPA 实体模型中的循环引用,FlexJson 是唯一可以对我的对象进行序列化的序列化程序。我想也许杰克逊会这样做,但我不确定。然后我把它放到 javascript 中,这就是我进行行着色和显示更改的地方。我只是觉得这是一个糟糕的关注点分离。行着色基于一些事情。其中之一是属性。这意味着当我传递 aaData、iTotalRows、iTotalDisplayRows(for jQuery, datatables) 时,我也必须传递属性。
        • (继续)。这意味着每次我更改数据表页面(数据表的服务器端处理)时,我都必须传递这些属性。然后我必须依靠 javascript 回调来进行行着色,我认为这比在我的模型中包含行颜色并在 Java 中进行处理要慢得多。也许我只是想多了,应该回到我开始的方式(以及你建议的方式......我相信)。我真的想让 JSON 序列化保持简单(这就是我的目标),但最终必须在某处应用行着色。
        【解决方案4】:
        ObjectNode factory = JsonNodeFactory.instance.objectNode();
        

        这很好用。我认为这是一种更简单的方法。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-10
          • 2014-08-22
          • 2018-11-01
          • 2020-04-12
          • 1970-01-01
          • 2011-06-26
          相关资源
          最近更新 更多