วิธีสร้าง JSON ใน Java อย่างคล่องแคล่ว


107

ฉันกำลังคิดบางอย่างเช่น:

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

ไลบรารี Java JSON ใดที่ดีที่สุดสำหรับการสร้างที่คล่องแคล่วประเภทนี้

อัปเดต : ฉันรวบรวม GSON และได้ผลลัพธ์เกือบตามที่ต้องการ ... ด้วยการผูกปมเดียว


1
ฉันไม่คิดว่าฉันเคยเห็นไลบรารี JSON ที่เป็นไปตามสไตล์นั้น บางทีคุณอาจขยายไลบรารีที่มีอยู่เพื่อทำสิ่งที่คุณต้องการ?
aroth

1
@aroth - ฉันกำลังเขียน Wrapper รอบ ๆ com.google.gson ในขณะที่เราพูด
ripper234

1
เกือบจะพร้อมแล้ว - stackoverflow.com/questions/8876271/…
ripper234

1
สร้าง "รัง" ของแผนที่และรายการที่เหมาะสมและทำให้เป็นอนุกรม หลีกเลี่ยงข้อความ "long chain polymer"
Hot Licks

คำตอบ:


143

ฉันใช้ไลบรารี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!"}

15
นี่ยังไม่คล่องเท่าไหร่
Vlad

เว็บที่คุณระบุใช้งานไม่ได้อีกต่อไป คุณช่วยอัปเดตได้ไหม
SašaZejnilović

13
@ วลาด - นี่คือสิ่งที่ผู้สร้างที่คล่องแคล่วแนะนำให้ฉัน คุณช่วยยกตัวอย่างการตั้งค่าที่คิดว่าดีกว่าได้ไหม
scubbo

4
นี่ยังคงเป็นตัวเลือกที่สะอาดกว่า เป็นเรื่องน่าขันที่นักพัฒนา Java ยังคงต้องหยุดชั่วคราวเพื่อหาตัวเลือกที่ดีที่สุดสำหรับการแยกวิเคราะห์ JSON / สร้างในปี 2020
mtyson

113

ดูสเปค Java EE 7 Json นี่เป็นวิธีที่ถูกต้อง:

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

8
สิ่งนี้ควรถูกระบุว่าเป็นคำตอบที่ถูกต้องในปี 2015 เนื่องจากเป็นส่วนหนึ่งของjavax.jsonJava 7 และใหม่กว่า
Sridhar Sarnobat

44
มันคือ Java EE API ไม่ใช่ Java SE
igorp1024


12
การพึ่งพา Mavenสำหรับjavax.jsonแพ็คเกจเดียวคืออันนี้
JeanValjean

1
สังเกตว่ามันสร้างวัตถุที่ไม่เปลี่ยนรูป
Kiran Kumar

12

ฉันเพิ่งสร้างไลบรารีสำหรับสร้างวัตถุ 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();

และด้วยความมหัศจรรย์ของ generics มันจะสร้างข้อผิดพลาดในการคอมไพล์หากคุณพยายามเพิ่มองค์ประกอบลงในอาร์เรย์ด้วยคีย์คุณสมบัติหรือองค์ประกอบให้กับวัตถุที่ไม่มีชื่อคุณสมบัติ:

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

8

หากคุณใช้ 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แต่คุณสามารถ desugar ได้อย่างง่ายดายเพื่อกรอกข้อมูลใน Java สำเร็จรูป


2
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()).

ฉันจะเพิ่มคนอื่น ๆ ตามคำขออย่างมีความสุขนอกจากนี้ยังค่อนข้างง่ายที่จะดำเนินการทีละคน


น่าเสียดายที่ไม่ได้อยู่ใน maven central ในเวลานี้โปรดดูที่github.com/HknL/JsonBuilder/issues/8
dschulten

1

ดูเหมือนว่าคุณอาจต้องการรับ json-lib:

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

ดักลาสคร็อกฟอร์ดเป็นคนที่คิดค้น JSON; ห้องสมุด Java ของเขาอยู่ที่นี่:

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

ดูเหมือนว่าคนที่ json-lib เลือกที่ Crockford ทิ้งไว้ ทั้งสองสนับสนุน JSON อย่างเต็มที่ทั้งการใช้งาน (เข้ากันได้เท่าที่ฉันสามารถบอกได้) โครงสร้าง JSONObject, JSONArray และ JSONFunction

'หวังว่าจะช่วย ..


รองรับไวยากรณ์ที่คล่องแคล่วหรือไม่?
ripper234


0

มันง่ายกว่าที่คุณคิดในการเขียนของคุณเองเพียงแค่ใช้อินเทอร์เฟซสำหรับJsonElementInterfaceวิธีการstring toJson()และคลาสนามธรรมที่AbstractJsonElementใช้อินเทอร์เฟซนั้น

จากนั้นสิ่งที่คุณต้องทำก็คือมีคลาสสำหรับJSONPropertyที่ใช้อินเทอร์เฟซและJSONValue(โทเค็นใด ๆ ) JSONArray([... ]) และJSONObject({... }) ที่ขยายคลาสนามธรรม

JSONObjectมีรายชื่อของJSONProperty's
JSONArrayมีรายชื่อของAbstractJsonElement' s

ฟังก์ชันเพิ่มของคุณในแต่ละรายการควรใช้รายการ vararg ของประเภทนั้นและส่งคืน this

ตอนนี้หากคุณไม่ชอบบางสิ่งคุณสามารถปรับแต่งได้

ประโยชน์ของอินเทอร์เฟซและคลาสนามธรรมคือJSONArrayไม่สามารถยอมรับคุณสมบัติ แต่JSONPropertyสามารถรับอ็อบเจ็กต์หรืออาร์เรย์ได้


0

คุณสามารถใช้หนึ่งในเอ็นจินเทมเพลต 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.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.