【问题标题】:Gson, JSON and the subtleties of LinkedTreeMapGson、JSON 和 LinkedTreeMap 的精妙之处
【发布时间】:2014-04-12 16:47:59
【问题描述】:

我最近开始使用 JSON 字符串,并被告知 Google 自己的库 Gson 是处理这些字符串的新方法。

我的理解是,JSON 字符串本质上是一个映射。其中每个变量都指向字符串中的一个值。

例如:

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

到目前为止,一切都很好。可以使用以下代码将诸如 JSON 字符串创建时间等信息分配给变量:

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

在简单的美中几乎是艺术。但这就是美丽结束的地方,我的困惑开始了。

以下是上述JSON字符串的扩展;

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

我的问题是这些“括号内的括号”如何用于JSONuser 部分?

如何将这些内括号中指定的值分配给变量?

谁能给我解释一下,或者用代码告诉我Gson如何处理这样的事情,以及我如何使用它?

简而言之,为什么...

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

...打印出null?

【问题讨论】:

    标签: java json gson


    【解决方案1】:

    忘记 Java。你需要先了解JSON format

    基本上就是这样

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

    您的第二个 JSON String(缺少 ")如下(使用 jsonlint.com 进行格式化)

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

    JSON是一个对象,外层{},包含三对,created_at是一个JSON字符串,id也是一个JSON字符串,user是一个JSON对象。该 JSON 对象包含另外三对都是 JSON 字符串。

    你问

    如何将这些内括号中指定的值分配给 变量?

    大多数高级 JSON 解析/生成库旨在将 JSON 转换为 Pojos 并返回。

    因此您可以将 JSON 格式映射到 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
    

    请注意@SerializedName,以便您可以继续为您的字段使用 Java 命名约定。

    您现在可以反序列化您的 JSON

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

    会打印

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

    显示所有字段都设置正确。

    谁能给我解释一下,或者用代码告诉我,Gson 如何处理这样的事情,以及我如何使用它?

    Gson 的源代码是免费提供的。你可以在网上找到它。它很复杂,源代码解释不适合这里。简而言之,它使用您提供的Class 对象来确定它将如何映射JSON 对。它查看相应类的字段。如果这些字段是其他类,则它会重复,直到它构建了它需要反序列化的所有内容的映射。


    简而言之,为什么...打印出 null?

    因为您的根 JSON 对象没有名称为 name 的对。不要使用Map,而是使用Gson 的JsonObject 类型。

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

    打印出来的

    somethingClever
    

    如果不是正确的类型,上述方法类可能会引发许多异常。例如,如果我们已经完成了

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

    它会失败,因为user 不是 JSON 数组。具体来说,它会抛出

    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)
    

    所以JsonElement 类(它是JsonObjectJsonArray 和其他一些的父类)提供了检查它是什么的方法。请参阅 javadoc。

    【讨论】:

    • 最好和最容易理解的答案。谢谢 Sotirios!
    • @ViRALiC 不客气。我最好的建议是在研究 Gson 之前先熟悉 JSON。
    【解决方案2】:

    对于那些来这里寻找将 LinkedTreeMap 转换为对象的方法的人:

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

    当我需要解析通用对象时,这对我很有用:

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

    但我不知道服务器要发送哪个对象。 objectFull 将成为 LinkedTreeMap

    【讨论】:

    • 谢谢。这救了我一个世界的悲伤!
    • 非常感谢,无法回答这个问题让我不得不接受采访。 atlast 找到了解决方案。
    【解决方案3】:

    JSON 字符串的结构如下:

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

    当您使用代码将值放入地图时:

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

    它具有以下关键值:

    created_at
    id
    user
    

    这就是为什么你可以使用map.get("created_at")

    现在,既然要获取用户名,就需要获取用户的地图:

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

    userMap 中,您将获得以下键值:

    id_str
    name
    screen_name
    

    现在,你可以获得username

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

    【讨论】:

    • 这个gson.fromJson(map.get("user") 将失败。 map.getUser("user") 返回 LinkedTreeMap
    • @AKS 如果名称有时在 String name = userMap.get("name"); 中不可用如何处理?
    【解决方案4】:

    user 本身就是一个JsonObject

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

    【讨论】:

    • 可能是这样,但这不起作用,因为 map 被声明为 Map&lt;String, String&gt;
    • 不,在这种情况下它将默认为LinkedTreeMap。 Gson 不知道JsonObject,除非你告诉它。
    【解决方案5】:

    好的。首先,JSON 是“JavaScript Object Notation”的缩写,因此您断言“JSON 字符串本质上是一个映射”是不正确的。 JSON 块是一个对象图,使用 JavaScript 语言语法进行描述。由于您试图将对象图强制转换为 String、Sting kay 值对的映射,因此这仅在任何给定的 JSON 对象图基本上就是这样的情况下才有效(所以不是很常见)。更成功的策略可能是gson.fromJson(),它将您的 JSON 转换为适当的 Java 对象图。

    【讨论】:

      猜你喜欢
      • 2011-08-01
      • 1970-01-01
      • 1970-01-01
      • 2016-10-29
      • 2015-12-03
      • 2015-03-01
      • 1970-01-01
      • 1970-01-01
      • 2017-10-15
      相关资源
      最近更新 更多