Gson,JSON和LinkedTreeMap的微妙之处

2022-09-03 03:20:58

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

我的理解是,字符串本质上是一个映射。其中,每个变量都指向字符串中的一个值。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\"}}";

我的问题是这些“括号内的括号”如何为该部分工作?userJSON

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

任何人都可以向我解释,或者在代码中向我展示如何处理这样的东西,以及我如何使用它?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


答案 1

忘掉 Java 吧。您需要首先了解 JSON 格式

这基本上就是它

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

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

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

JSON 是一个对象,外部 ,它包含三对,它是一个 JSON 字符串,也是一个 JSON 字符串,它是一个 JSON 对象。该 JSON 对象包含另外三个都是 JSON 字符串的对。{}created_atiduser

你问

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

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


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

因为您的根 JSON 对象 没有与 name .不要使用 ,请使用 Gson 的类型。nameMapJsonObject

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

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

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 类(它是 、 和其他一些类的父类)提供了检查它是什么的方法。请参阅 javadoc。JsonObjectJsonArray


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

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