Comment construire couramment JSON en Java?

107

Je pense à quelque chose comme:

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

Quelle bibliothèque Java JSON est la meilleure pour ce type de construction fluide?

Mise à jour : j'ai enveloppé GSON et j'ai presque obtenu le résultat souhaité ... avec un accroc .

ripper234
la source
1
Je ne pense pas avoir vu de bibliothèque JSON qui suit ce style. Peut-être pourriez-vous étendre une bibliothèque existante pour faire ce que vous voulez?
aroth
1
@aroth - J'écris un wrapper autour de com.google.gson pendant que nous parlons.
ripper234
1
Presque prêt - stackoverflow.com/questions/8876271
...
1
Construisez le «nid» approprié de cartes et de listes et sérialisez-le. Évitez les déclarations «polymère à longue chaîne».
Hot Licks

Réponses:

141

J'utilise la bibliothèque org.json et je l' ai trouvée agréable et conviviale.

Exemple:

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

PRODUCTION:

{"JSON2":"Hello my World!","JSON3":{"key1":"value1"},"JSON1":"Hello World!"}
dku.rajkumar
la source
15
Ce n'est pas très courant.
Vlad
Le site Web que vous avez fourni ne fonctionne plus. Pourriez-vous le mettre à jour?
Saša Zejnilović
13
@Vlad - c'est exactement ce que me suggèrent les constructeurs couramment. Pouvez-vous donner un exemple d'une configuration que vous pensez être meilleure?
scubbo
3
C'est toujours l'option la plus propre. Il est ridicule que les développeurs Java doivent encore faire une pause pour trouver la meilleure option pour l'analyse / compilation JSON en 2020.
mtyson
113

Consultez la spécification Java EE 7 Json . C'est le bon chemin:

String json = Json.createObjectBuilder()
            .add("key1", "value1")
            .add("key2", "value2")
            .build()
            .toString();
Yumarx Polanco
la source
8
Cela devrait être marqué comme la bonne réponse en 2015 car cela fait partie de javax.jsonJava 7 et versions ultérieures.
Sridhar Sarnobat
42
Il s'agit de l'API Java EE, pas de Java SE.
igorp1024
Une idée comment créer un objet JsonString à partir d'un objet String dans l'API javax.json?
Raymond
4
dépendance maven
ankitkpd
12
La dépendance Maven pour le javax.jsonpackage unique est celle-ci
JeanValjean
12

J'ai récemment créé une bibliothèque pour créer couramment des objets Gson:

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

Cela fonctionne comme ceci:

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

Et grâce à la magie des génériques, il génère des erreurs de compilation si vous essayez d'ajouter un élément à un tableau avec une clé de propriété ou un élément à un objet sans nom de propriété:

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.

Enfin, l'API prend en charge le mappage qui vous permet de mapper les objets de votre domaine vers JSON. Le but étant que lorsque Java8 sera publié, vous pourrez faire quelque chose comme ceci:

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

Si vous utilisez Jackson pour JsonNodeconstruire beaucoup de code, vous pouvez être intéressant dans l'ensemble d'utilitaires suivant. L'avantage de leur utilisation est qu'ils prennent en charge un style de chaînage plus naturel qui montre mieux la structure du JSON en construction.

Voici un exemple d'utilisation:

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

...

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

Ce qui équivaut au JSON suivant:

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

Voici les classes:

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

  }

}

Notez que l'implémentation utilise Lombok , mais vous pouvez facilement la désugarer pour remplir le standard Java.

Btiernay
la source
2
String json = new JsonBuilder(new GsonAdapter())
  .object("key1", "value1")
  .object("key2", "value2")
  .object("key3")
    .object("innerKey1", "value3")
    .build().toString();

Si vous pensez que la solution ci-dessus est élégante, essayez ma bibliothèque JsonBuilder . Il a été créé pour permettre une manière de construire des structures json pour de nombreux types de bibliothèques Json. Les implémentations actuelles incluent Gson, Jackson et MongoDB. Pour ie. Jackson vient d'échanger:

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

J'en ajouterai volontiers d'autres sur demande, c'est aussi assez facile à implémenter un par soi-même.

Homyk
la source
malheureusement pas dans maven central pour le moment, voir github.com/HknL/JsonBuilder/issues/8
dschulten
1

Il semble que vous souhaitiez probablement mettre la main sur json-lib:

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

Douglas Crockford est le type qui a inventé JSON; sa bibliothèque Java est ici:

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

On dirait que les gens de json-lib ont repris là où Crockford s'était arrêté. Les deux prennent entièrement en charge JSON, les deux utilisent (compatibles, pour autant que je sache) les constructions JSONObject, JSONArray et JSONFunction.

'J'espère que cela pourra aider ..

paulsm4
la source
Prend-il en charge la syntaxe fluide?
ripper234
0

c'est beaucoup plus facile que vous ne le pensez d'écrire le vôtre, utilisez simplement une interface pour JsonElementInterfaceavec une méthode string toJson(), et une classe abstraite AbstractJsonElementimplémentant cette interface,

alors tout ce que vous avez à faire est d'avoir une classe pour JSONPropertyqui implémente l'interface, et JSONValue(tout jeton), JSONArray([...]) et JSONObject({...}) qui étendent la classe abstraite

JSONObjecta une liste de JSONProperty's
JSONArraya une liste de AbstractJsonElement' s

votre fonction add dans chacun devrait prendre une liste de vararg de ce type et retourner this

maintenant si vous n'aimez pas quelque chose, vous pouvez simplement le modifier

l'avantage de l'interface et de la classe abstraite est de JSONArrayne pas accepter de propriétés, mais JSONPropertypeut accepter des objets ou des tableaux

Austin_Anderson
la source