简体   繁体   English

Gson、JSON 和 LinkedTreeMap 的微妙之处

[英]Gson, JSON and the subtleties of LinkedTreeMap

I've recently started playing around with JSON strings, and was told that Google's own library, Gson , is the new and hip way of dealing with these.我最近开始玩弄JSON字符串,并被告知 Google 自己的库Gson是处理这些字符串的新方法。

The way I've understood it, is that a JSON string is essentially a map.我的理解是, JSON字符串本质上是一个地图。 Where each variable points to a value in the string.其中每个变量指向字符串中的一个值。

For example:例如:

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

Thus far, all is well.到目前为止,一切都很好。 Information such as when this JSON string was created, can be assigned to a variable with the following code:可以使用以下代码将诸如创建此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");

It's almost artistic in in simple beauty.它在简单的美中几乎是艺术的。 But this is where the beauty ends and my confusion begins.但这就是美丽结束的地方,我的困惑开始了。

The following is an extension of the above JSON string;以下是上述JSON字符串的扩展;

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

My question is how these "brackets within brackets" work for the user section of the JSON ?我的问题是这些“括号内的括号”如何用于JSONuser部分?

How could I assign the values specified within these inner-brackets to variables?如何将这些内括号中指定的值分配给变量?

Can anyone explain to me, or show me in code, how Gson handles stuff like this, and how I can use it?任何人都可以向我解释,或用代码向我展示Gson如何处理这样的东西,以及我如何使用它?

In short, why does...简而言之,为什么...

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

... print out null ? ...打印出null

Forget about Java.忘记 Java。 You need to first understand the JSON format .您需要先了解JSON 格式

This is basically it基本上就是这样

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

Your second JSON String (which has a missing " ) is the following (use jsonlint.com to format)您的第二个 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"
    }
}

The JSON is an object, outer {} , that contains three pairs, created_at which is a JSON string, id which is also a JSON string, and user which is a JSON object. JSON 是一个对象,外层{} ,它包含三对, created_at是一个 JSON 字符串, id也是一个 JSON 字符串,以及user是一个 JSON 对象。 That JSON object contains three more pairs which are all JSON strings.该 JSON 对象包含另外三对都是 JSON 字符串。

You asked你问

How could I assign the values specified within these inner-brackets to variables?如何将这些内括号中指定的值分配给变量?

Most advanced JSON parsing/generating libraries are meant to convert JSON to Pojos and back.大多数高级 JSON 解析/生成库旨在将 JSON 转换为 Pojos 并返回。

So you could map your JSON format to Java classes.因此,您可以将 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

Note the @SerializedName so that you can keep using Java naming conventions for your fields.请注意@SerializedName以便您可以继续为您的字段使用 Java 命名约定。

You can now deserialize your JSON您现在可以反序列化您的 JSON

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

would print会打印

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

showing that all the fields were set correctly.显示所有字段都设置正确。

Can anyone explain to me, or show me in code, how Gson handles stuff like this, and how I can use it?谁能向我解释,或用代码向我展示 Gson 如何处理这样的东西,以及我如何使用它?

The source code of Gson is freely available. Gson 的源代码是免费提供的。 You can find it online.你可以在网上找到它。 It is complex and a source code explanation wouldn't fit here.它很复杂,源代码解释不适合这里。 Simply put, it uses the Class object you provide to determine how it will map the JSON pairs.简而言之,它使用您提供的Class对象来确定它将如何映射 JSON 对。 It looks at the corresponding class's fields.它查看相应类的字段。 If those fields are other classes, then it recurs until it has constructed a map of everything it needs to deserialize.如果这些字段是其他类,则它会重复执行,直到它构建了反序列化所需的所有内容的映射。


In short, why does...print out null?简而言之,为什么...打印出空值?

Because your root JSON object, doesn't have a pair with name name .因为您的根 JSON 对象没有名称为name的对。 Instead of using Map , use Gson's JsonObject type.不要使用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);

which prints哪个打印

somethingClever

The above method class could have thrown a number of exceptions if they weren't the right type.如果它们的类型不正确,上面的方法类可能会抛出许多异常。 If, for example, we had done例如,如果我们做了

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

it would fail because user is not a JSON array.它会失败,因为user不是 JSON 数组。 Specifically, it would throw具体来说,它会抛出

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)

So the JsonElement class (which is the parent class of JsonObject , JsonArray , and a few others) provides methods to check what it is.所以JsonElement类(它是JsonObjectJsonArray和其他一些的父类)提供了检查它是什么的方法。 See the javadoc.请参阅 javadoc。

For people that come here searching for a way to convert LinkedTreeMap to object :对于来这里寻找将 LinkedTreeMap 转换为 object 的方法的人

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

This was usefull for me when i needed to parse an generic object like:当我需要解析一个通用对象时,这对我很有用:

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

But i don't know which object the server was going to send.但我不知道服务器要发送哪个对象。 The objectFull will become a LinkedTreeMap objectFull 将成为 LinkedTreeMap

The JSON string has following structure: JSON 字符串具有以下结构:

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

When you put the values in the map using the code:当您使用代码将值放入地图时:

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

It has following key values:它具有以下关键值:

created_at
id
user

and that's why you are able to use map.get("created_at") .这就是为什么您可以使用map.get("created_at")

Now, since you want to get the name of the user, you need to get the map of user:现在,由于要获取用户的名称,因此需要获取用户的地图:

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

In the userMap , you would get following key values:userMap ,您将获得以下键值:

id_str
name
screen_name

Now, you can get the name of the user现在,您可以获取username

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

user是一个JsonObject本身:

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

Ok.好的。 First of all JSON is short for "JavaScript Object Notation" so your assertion that "a JSON string is essentially a map" is incorrect.首先,JSON 是“JavaScript Object Notation”的缩写,因此您关于“JSON 字符串本质上是地图”的断言是不正确的。 A JSON block is an object graph, described using the JavaScript language syntax. JSON 块是一个对象图,使用 JavaScript 语言语法进行描述。 Since your trying to coerce an object graph to a Map of String, Sting kay value pairs, this is only going to work in cases where any given JSON object graph is essentially just that (so not very often).由于您试图将对象图强制转换为字符串映射,Sting kay 值对,因此这仅在任何给定的 JSON 对象图本质上就是这样的情况下才有效(所以不是很常见)。 A more successful strategy would probably be gson.fromJson() which will convert your JSON to a proper Java object graph.更成功的策略可能是gson.fromJson() ,它将您的 JSON 转换为适当的 Java 对象图。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM