web-dev-qa-db-fra.com

Gson, JSON et les subtilités de LinkedTreeMap

J'ai récemment commencé à jouer avec les chaînes JSON et on m'a dit que la bibliothèque de Google, Gson, était la nouvelle façon branchée de gérer ces problèmes.

D'après ce que j'ai compris, une chaîne JSON est essentiellement une carte. Où chaque variable pointe vers une valeur de la chaîne.

Par exemple:

String jsonInput2 = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\"}

Jusqu'ici tout va bien. Des informations telles que la date de création de cette chaîne JSON peuvent être affectées à une variable avec le code suivant:

Gson gson = new Gson();

Map<String, String> map = new HashMap<String, String>();

map = (Map<String, String>) gson.fromJson(jsonInput, map.getClass());

String createdAt = map.get("created_at");

C'est presque artistique dans la beauté simple. Mais c'est là que la beauté se termine et que commence ma confusion.

Ce qui suit est une extension de la chaîne JSON ci-dessus;

String jsonInput2 = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\",\"user\":{\"id_str\":\"366301747\",\"name\":\"somethingClever\",\"screen_name\":\"somethingCoolAndClever\"}}";

Ma question est de savoir comment ces "crochets entre crochets" fonctionnent pour la section user de la JSON?

Comment pourrais-je affecter les valeurs spécifiées dans ces parenthèses aux variables?

Quelqu'un peut-il m'expliquer, ou me montrer dans le code, comment Gson gère ce genre de choses et comment je peux les utiliser?

En bref, pourquoi ...

String jsonInput = "{\"created_at\":\"Sat Feb 08 15:37:37 +0000 2014\",\"id\":432176397474623489\",\"user\":{\"id_str\":\"366301747\",\"name\":\"somethingClever\",\"screen_name\":\"somethingCoolAndClever\"}}";

Gson gson = new Gson();

Map<String, String> map = new HashMap<String, String>();

map = (Map<String, String>) gson.fromJson(jsonInput, map.getClass());

String name = map.get("name");

System.out.println(name);

... imprimer null?

8
ViRALiC

Oubliez Java. Vous devez d’abord comprendre le format JSON . C'est fondamentalement ça

object
    {}
    { members }
members
    pair
    pair , members
pair
    string : value
array
    []
    [ elements ]
elements
    value 
    value , elements
value
    string
    number
    object
    array
    true
    false
    null

Votre deuxième JSON String (qui a un " manquant) est le suivant (utilisez jsonlint.com pour formater)

{
    "created_at": "Sat Feb 08 15:37:37 +0000 2014",
    "id": "432176397474623489",
    "user": {
        "id_str": "366301747",
        "name": "somethingClever",
        "screen_name": "somethingCoolAndClever"
    }
}

Le JSON est un objet, {} extérieur, qui contient trois paires, created_at qui est une chaîne JSON, id qui est également une chaîne JSON et user qui est un objet JSON. Cet objet JSON contient trois autres paires, qui sont toutes des chaînes JSON.

Tu as demandé

Comment attribuer les valeurs spécifiées entre ces crochets aux variables ?

La plupart des bibliothèques d'analyse/génération JSON avancées sont conçues pour convertir JSON en Pojos et inversement.

Vous pouvez donc mapper votre format JSON sur les classes Java.

class Pojo {
    @SerializedName("created_at")
    private String createdAt;
    private String id;
    private User user;
}

class User {
    @SerializedName("id_str")
    private String idStr;
    private String name;
    @SerializedName("screen_name")
    private String screenName;
}

// with appropriate getters, setters, and a toString() method

Notez le @SerializedName pour que vous puissiez continuer à utiliser les conventions de dénomination Java pour vos champs.

Vous pouvez maintenant désérialiser votre JSON

Gson gson = new Gson();
Pojo pojo = gson.fromJson(jsonInput2, Pojo.class);
System.out.println(pojo);

serait imprimer

Pojo [createdAt=Sat Feb 08 15:37:37 +0000 2014, id=432176397474623489", user=User [idStr=366301747, name=somethingClever, screenName=somethingCoolAndClever]]

montrant que tous les champs ont été définis correctement.

Quelqu'un peut-il m'expliquer ou me montrer, dans le code, comment Gson gère ce genre de choses et comment je peux les utiliser?

Le code source de Gson est disponible gratuitement. Tu peux le trouver en ligne. C'est complexe et une explication de code source ne conviendrait pas ici. En termes simples, il utilise l'objet Class que vous fournissez pour déterminer comment il mappera les paires JSON. Il examine les champs de la classe correspondante. Si ces champs sont d’autres classes, il se reproduit jusqu’à ce qu’il ait construit une carte de tout ce dont il a besoin pour être désérialisé.


En bref, pourquoi est-ce que ... affiche null?

Parce que votre objet JSON racine n'a pas de paire nommée name. Au lieu d'utiliser Map, utilisez le type JsonObject de Gson.

JsonObject jsonObject = new Gson().fromJson(jsonInput2, JsonObject.class);

String name = jsonObject.get("user")       // get the 'user' JsonElement
                        .getAsJsonObject() // get it as a JsonObject
                        .get("name")       // get the nested 'name' JsonElement
                        .getAsString();    // get it as a String
System.out.println(name);

qui imprime

somethingClever

La classe de méthode ci-dessus aurait pu générer un certain nombre d'exceptions si elles n'étaient pas du type approprié. Si, par exemple, nous avions fait

String name = jsonObject.get("user")       // get the 'user' JsonElement
                        .getAsJsonArray()  // get it as a JsonArray

cela échouerait car user n'est pas un tableau JSON. Plus précisément, il jetterait

Exception in thread "main" Java.lang.IllegalStateException: This is not a JSON Array.
    at com.google.gson.JsonElement.getAsJsonArray(JsonElement.Java:106)
    at com.spring.Example.main(Example.Java:19)

Ainsi, la classe JsonElement (qui est la classe parente de JsonObject, JsonArray et quelques autres) fournit des méthodes pour vérifier ce que c'est. Voir le javadoc.

31

La chaîne JSON a la structure suivante:

{
    created_at: "",
    id: "",
    user: {
            id_str: "",
            name: "",
            screen_name: ""
    }
 }

Lorsque vous mettez les valeurs dans la carte en utilisant le code:

Map<String, Object> map = new HashMap<String, Object>();
map = (Map<String, Object>) gson.fromJson(jsonInput, map.getClass());

Il a les valeurs clés suivantes:

created_at
id
user

et c’est pourquoi vous pouvez utiliser map.get("created_at").

Maintenant, puisque vous voulez obtenir le nom de l'utilisateur, vous devez obtenir la carte de l'utilisateur:

LinkedTreeMap<String, Object> userMap = (LinkedTreeMap<String, Object>) map.get("user");

Dans la userMap, vous obtiendrez les valeurs de clé suivantes:

id_str
name
screen_name

Maintenant, vous pouvez obtenir la name de la user

String name = userMap.get("name");
4
AKS

Pour les personnes qui viennent ici à la recherche d'un moyen de convertir LinkedTreeMap en objet:

MyClass object = new Gson().fromJson(new Gson().toJson(((LinkedTreeMap<String, Object>) theLinkedTreeMapObject)), MyClass .class)

Cela m'a été utile lorsque j'ai eu besoin d'analyser un objet générique tel que:

Class fullObject {
  private String name;
  private String objectType;
  private Object objectFull;   
}

Mais je ne sais pas quel objet le serveur allait envoyer. L'objetFull deviendra un LinkedTreeMap

3
sagits

user est une JsonObject elle-même:

JsonObject user = map.get("user");
1
Smutje

D'accord. Tout d'abord, JSON est l'abréviation de "JavaScript Object Notation". Votre affirmation selon laquelle "une chaîne JSON est essentiellement une carte" est incorrecte. Un bloc JSON est un graphe d'objet, décrit à l'aide de la syntaxe du langage JavaScript. Étant donné que vous essayez de contraindre un graphe d'objet à une paire de valeurs Sting kay, il ne fonctionnera que dans les cas où un graphe d'objet JSON donné est essentiellement ce qu'il est (donc pas très souvent). Une stratégie plus efficace serait probablement gson.fromJson() qui convertira votre JSON en un graphe d'objet Java approprié.

0
Mikkel Løkke