Wie erstelle ich JSON fließend in Java?

106

Ich denke an etwas wie:

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

Welche Java JSON-Bibliothek eignet sich am besten für diese Art von fließendem Erstellen?

Update : Ich habe GSON verpackt und fast das gewünschte Ergebnis erzielt ... mit einem Problem .

ripper234
quelle
1
Ich glaube nicht, dass ich eine JSON-Bibliothek gesehen habe, die diesem Stil folgt. Vielleicht könnten Sie eine vorhandene Bibliothek erweitern, um das zu tun, was Sie wollen?
aroth
1
@aroth - Ich schreibe gerade einen Wrapper um com.google.gson.
Ripper234
1
Fast fertig - stackoverflow.com/questions/8876271/…
ripper234
1
Erstellen Sie das entsprechende "Nest" aus Karten und Listen und serialisieren Sie es. Vermeiden Sie Aussagen zu "langkettigen Polymeren".
Hot Licks

Antworten:

140

Ich benutze die Bibliothek org.json und fand sie nett und freundlich.

Beispiel:

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

AUSGABE:

{"JSON2":"Hello my World!","JSON3":{"key1":"value1"},"JSON1":"Hello World!"}
dku.rajkumar
quelle
15
Das ist nicht sehr fließend.
Vlad
Das von Ihnen bereitgestellte Web funktioniert nicht mehr. Würde es Ihnen etwas ausmachen, es zu aktualisieren?
Saša Zejnilović
13
@Vlad - genau das schlagen mir fließende Bauherren vor. Können Sie ein Beispiel für ein Setup nennen, das Sie für besser halten?
Scubbo
3
Dies ist immer noch die sauberere Option. Es ist lächerlich, dass Java-Entwickler noch eine Pause einlegen müssen, um die beste Option für JSON-Analyse / Build im Jahr 2020 zu finden.
Mtyson
112

Siehe die Java EE 7 Json-Spezifikation . Das ist der richtige Weg:

String json = Json.createObjectBuilder()
            .add("key1", "value1")
            .add("key2", "value2")
            .build()
            .toString();
Yumarx Polanco
quelle
8
Dies sollte 2015 als die richtige Antwort markiert werden, da dies Teil von javax.jsonJava 7 und höher ist.
Sridhar Sarnobat
42
Es ist Java EE API, nicht Java SE.
igorp1024
Haben Sie eine Idee, wie Sie ein JsonString-Objekt aus einem String-Objekt in der javax.json-API erstellen können?
Raymond
3
Maven-Abhängigkeit: mvnrepository.com/artifact/javax/javaee-api/7.0
ankitkpd
12
Maven Abhängigkeit für das einzige javax.jsonPaket ist dieses
JeanValjean
12

Ich habe kürzlich eine Bibliothek zum fließenden Erstellen von Gson-Objekten erstellt:

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

Es funktioniert so:

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

Und durch die Magie der Generika werden Kompilierungsfehler generiert, wenn Sie versuchen, einem Array mit einem Eigenschaftsschlüssel ein Element oder einem Objekt ohne Eigenschaftsnamen ein Element hinzuzufügen:

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.

Schließlich gibt es in der API Unterstützung für die Zuordnung, mit der Sie Ihre Domänenobjekte JSON zuordnen können. Das Ziel ist, dass Sie mit der Veröffentlichung von Java8 Folgendes tun können:

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

Wenn Sie mit Jackson viel JsonNodeCode einbauen, sind Sie möglicherweise an den folgenden Dienstprogrammen interessiert. Der Vorteil ihrer Verwendung besteht darin, dass sie einen natürlicheren Verkettungsstil unterstützen, der die Struktur des im Bau befindlichen JSON besser zeigt.

Hier ist ein Anwendungsbeispiel:

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

...

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

Welches entspricht dem folgenden JSON:

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

Hier sind die Klassen:

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

  }

}

Beachten Sie, dass die Implementierung Lombok verwendet , Sie es jedoch problemlos deaktivieren können, um das Java-Boilerplate auszufüllen.

Übrigens
quelle
2
String json = new JsonBuilder(new GsonAdapter())
  .object("key1", "value1")
  .object("key2", "value2")
  .object("key3")
    .object("innerKey1", "value3")
    .build().toString();

Wenn Sie der Meinung sind, dass die oben genannte Lösung elegant ist, probieren Sie bitte meine JsonBuilder-Bibliothek aus . Es wurde erstellt, um eine Möglichkeit zum Erstellen von Json-Strukturen für viele Arten von Json-Bibliotheken zu ermöglichen. Aktuelle Implementierungen umfassen Gson, Jackson und MongoDB. Für dh. Jackson tauscht einfach:

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

Gerne füge ich auf Anfrage weitere hinzu, es ist auch ganz einfach, eine selbst zu implementieren.

Homyk
quelle
Leider nicht in Maven Central zu diesem Zeitpunkt, siehe github.com/HknL/JsonBuilder/issues/8
dschulten
1

Es hört sich so an, als ob Sie wahrscheinlich json-lib kennenlernen möchten:

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

Douglas Crockford ist der Typ, der JSON erfunden hat; seine Java-Bibliothek ist hier:

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

Es hört sich so an, als hätten die Leute von json-lib dort angefangen, wo Crockford aufgehört hat. Beide unterstützen JSON vollständig, beide verwenden (soweit ich das beurteilen kann) JSONObject-, JSONArray- und JSONFunction-Konstrukte (kompatibel).

'Hoffentlich hilft das ..

paulsm4
quelle
Unterstützt es fließende Syntax?
Ripper234
0

Es ist viel einfacher als Sie denken, Ihre eigenen zu schreiben. Verwenden Sie einfach eine Schnittstelle für JsonElementInterfaceeine Methode string toJson()und eine abstrakte Klasse, AbstractJsonElementdie diese Schnittstelle implementiert.

Dann müssen Sie nur noch eine Klasse haben JSONProperty, die die Schnittstelle implementiert, und JSONValue(jedes Token), JSONArray([...]) und JSONObject({...}), die die abstrakte Klasse erweitern

JSONObjecthat eine Liste von JSONProperty's
JSONArrayhat eine Liste von AbstractJsonElement' s

Ihre Add-Funktion in jedem sollte eine Vararg-Liste dieses Typs verwenden und zurückgeben this

Wenn Sie etwas nicht mögen, können Sie es einfach optimieren

Der Vorteil der Schnittstelle und der abstrakten Klasse besteht darin, dass JSONArraysie keine Eigenschaften akzeptieren können, aber JSONPropertyObjekte oder Arrays akzeptieren können

Austin_Anderson
quelle