【问题标题】:How to fluently build JSON in Java? [closed]如何在 Java 中流畅地构建 JSON?
【发布时间】:2012-02-11 03:54:22
【问题描述】:

我在想这样的事情:

String json = new JsonBuilder()
  .add("key1", "value1")
  .add("key2", "value2")
  .add("key3", new JsonBuilder()
    .add("innerKey1", "value3"))
  .toJson();

哪种 Java JSON 库最适合这种流畅的构建?

更新:我封装了 GSON,几乎得到了想要的结果...with one hitch

【问题讨论】:

  • 我认为我没有见过任何遵循这种风格的 JSON 库。也许您可以扩展现有的库来做您想做的事?
  • @aroth - 我正在为 com.google.gson 编写一个包装器。
  • 构造地图和列表的适当“巢”并将其序列化。避免使用“长链聚合物”的说法。

标签: java json


【解决方案1】:

我正在使用org.json 库,发现它非常友好。

例子:

String jsonString = new JSONObject()
                  .put("JSON1", "Hello World!")
                  .put("JSON2", "Hello my World!")
                  .put("JSON3", new JSONObject().put("key1", "value1"))
                  .toString();

System.out.println(jsonString);

输出:

{"JSON2":"Hello my World!","JSON3":{"key1":"value1"},"JSON1":"Hello World!"}

【讨论】:

  • 这个不太流利。
  • 您提供的网络不再可用。你介意更新一下吗?
  • @Vlad - 这正是流利的建设者对我的建议。您能否提供一个您认为更好的设置示例?
  • 这仍然是更简洁的选项。荒谬的是,Java 开发人员仍然不得不停下来寻找 2020 年 JSON 解析/构建的最佳选择。
【解决方案2】:

请参阅Java EE 7 Json specification。 这是正确的方法:

String json = Json.createObjectBuilder()
            .add("key1", "value1")
            .add("key2", "value2")
            .build()
            .toString();

【讨论】:

【解决方案3】:

我最近创建了一个库,用于流畅地创建 Gson 对象:

http://jglue.org/fluent-json/

它是这样工作的:

  JsonObject jsonObject = JsonBuilderFactory.buildObject() //Create a new builder for an object
  .addNull("nullKey")                            //1. Add a null to the object

  .add("stringKey", "Hello")                     //2. Add a string to the object
  .add("stringNullKey", (String) null)           //3. Add a null string to the object

  .add("numberKey", 2)                           //4. Add a number to the object
  .add("numberNullKey", (Float) null)            //5. Add a null number to the object

  .add("booleanKey", true)                       //6. Add a boolean to the object
  .add("booleanNullKey", (Boolean) null)         //7. Add a null boolean to the object

  .add("characterKey", 'c')                      //8. Add a character to the object
  .add("characterNullKey", (Character) null)     //9. Add a null character to the object

  .addObject("objKey")                           //10. Add a nested object
    .add("nestedPropertyKey", 4)                 //11. Add a nested property to the nested object
    .end()                                       //12. End nested object and return to the parent builder

  .addArray("arrayKey")                          //13. Add an array to the object
    .addObject()                                 //14. Add a nested object to the array
      .end()                                     //15. End the nested object
    .add("arrayElement")                         //16. Add a string to the array
    .end()                                       //17. End the array

    .getJson();                                  //Get the JsonObject

String json = jsonObject.toString();

通过泛型的魔力,如果您尝试将元素添加到具有属性键的数组或将元素添加到没有属性名称的对象,则会产生编译错误:

JsonObject jsonArray = JsonBuilderFactory.buildArray().addObject().end().add("foo", "bar").getJson(); //Error: tried to add a string with property key to array.
JsonObject jsonObject = JsonBuilderFactory.buildObject().addArray().end().add("foo").getJson(); //Error: tried to add a string without property key to an object.
JsonArray jsonArray = JsonBuilderFactory.buildObject().addArray("foo").getJson(); //Error: tried to assign an object to an array.
JsonObject jsonObject = JsonBuilderFactory.buildArray().addObject().getJson(); //Error: tried to assign an object to an array.

最后,API 中支持映射,允许您将域对象映射到 JSON。目标是当 Java8 发布时,您将能够执行以下操作:

Collection<User> users = ...;
JsonArray jsonArray = JsonBuilderFactory.buildArray(users, { u-> buildObject()
                                                                 .add("userName", u.getName())
                                                                 .add("ageInYears", u.getAge()) })
                                                                 .getJson();

【讨论】:

    【解决方案4】:

    如果您正在使用 Jackson 执行大量 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 样板。

    【讨论】:

      【解决方案5】:
      String json = new JsonBuilder(new GsonAdapter())
        .object("key1", "value1")
        .object("key2", "value2")
        .object("key3")
          .object("innerKey1", "value3")
          .build().toString();
      

      如果您认为上述解决方案很优雅,请尝试我的JsonBuilder lib。创建它是为了允许一种为多种类型的 Json 库构建 json 结构的方法。当前的实现包括 Gson、Jackson 和 MongoDB。对于即。杰克逊只是交换:

      String json = new JsonBuilder(new JacksonAdapter()).
      

      我会很乐意根据要求添加其他的,也很容易自己实现。

      【讨论】:

      【解决方案6】:

      听起来你可能想获得 json-lib:

      http://json-lib.sourceforge.net/

      Douglas Crockford 是 JSON 的发明者;他的 Java 库在这里:

      http://www.json.org/java/

      听起来 json-lib 的人从 Crockford 停止的地方接了过来。两者都完全支持 JSON,都使用(据我所知兼容)JSONObject、JSONArray 和 JSONFunction 构造。

      '希望有帮助..

      【讨论】:

      • 是否支持流畅的语法?
      【解决方案7】:

      reference implementation 包含一个流畅的界面。查看JSONWriter 及其实现toString 的子类JSONStringer

      【讨论】:

        【解决方案8】:

        您可以使用其中一种 Java 模板引擎。 我喜欢这种方法,因为您将逻辑与视图分开。

        Java 8+:

        <dependency>
          <groupId>com.github.spullara.mustache.java</groupId>
          <artifactId>compiler</artifactId>
          <version>0.9.6</version>
        </dependency>
        

        Java 6/7:

        <dependency>
          <groupId>com.github.spullara.mustache.java</groupId>
          <artifactId>compiler</artifactId>
          <version>0.8.18</version>
        </dependency>
        

        示例模板文件:

        {{#items}}
        Name: {{name}}
        Price: {{price}}
          {{#features}}
          Feature: {{description}}
          {{/features}}
        {{/items}}
        

        可能由一些支持代码提供支持:

        public class Context {
          List<Item> items() {
            return Arrays.asList(
              new Item("Item 1", "$19.99", Arrays.asList(new Feature("New!"), new Feature("Awesome!"))),
              new Item("Item 2", "$29.99", Arrays.asList(new Feature("Old."), new Feature("Ugly.")))
            );
          }
        
          static class Item {
            Item(String name, String price, List<Feature> features) {
              this.name = name;
              this.price = price;
              this.features = features;
            }
            String name, price;
            List<Feature> features;
          }
        
          static class Feature {
            Feature(String description) {
               this.description = description;
            }
            String description;
          }
        }
        

        会导致:

        Name: Item 1
        Price: $19.99
          Feature: New!
          Feature: Awesome!
        Name: Item 2
        Price: $29.99
          Feature: Old.
          Feature: Ugly.
        

        【讨论】:

          【解决方案9】:

          我来这里是为了寻找一种使用流利的 json 构建器编写 rest 端点测试的好方法。在我的例子中,我使用 JSONObject 来构建一个专门的构建器。它需要一些工具,但使用起来非常好:

          import lombok.SneakyThrows;
          import org.json.JSONObject;
          
          public class MemberJson extends JSONObject {
          
              @SneakyThrows
              public static MemberJson builder() {
                  return new MemberJson();
              }
          
              @SneakyThrows
              public MemberJson name(String name) {
                  put("name", name);
                  return this;
              }
          
          }
          
          MemberJson.builder().name("Member").toString();
          

          【讨论】:

            【解决方案10】:

            编写自己的代码比您想象的要容易得多,只需使用 JsonElementInterface 的接口和方法 string toJson(),以及实现该接口的抽象类 AbstractJsonElement

            那么你所要做的就是为JSONProperty创建一个实现接口的类,以及JSONValue(任何令牌)、JSONArray([...])和JSONObject({.. .}) 扩展抽象类

            JSONObject 有一个JSONProperty 的列表
            JSONArray 有一个AbstractJsonElement 的列表

            您在每个中的 add 函数应该采用该类型的 vararg 列表,并返回 this

            现在如果你不喜欢某些东西,你可以调整它

            接口和抽象类的好处是JSONArray不能接受属性,但JSONProperty可以接受对象或数组

            【讨论】:

              【解决方案11】:

              Underscore-java 库有 json builder。

              import com.github.underscore.U;
              
              public static void main(String[] args) {
                String json = U.objectBuilder()
                  .add("key1", "value1")
                  .add("key2", "value2")
                  .add("key3", U.objectBuilder()
                    .add("innerKey1", "value3"))
                  .toJson();
                System.out.println(json);
              }
              
              Output:
              {
                "key1": "value1",
                "key2": "value2",
                "key3": {
                  "innerKey1": "value3"
                }
              }
              

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-09-19
                • 1970-01-01
                • 2018-04-29
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多