我最近开始摆弄
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\"}}";
我的问题是这些“括号内的括号”如何用于
user
的 JSON
部分?
如何将这些内括号中指定的值分配给变量?
任何人都可以向我解释,或者用代码向我展示,
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格式。
基本上就是这样了
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
(缺少 "
)如下(使用 https://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
(JavaDoc),以便您可以继续为您的字段使用 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
(JavaDoc) 类(它是 JsonObject
、JsonArray
和其他一些类的父类)提供了方法来检查它是什么。请参阅 javadoc。
对于来这里寻找方法将 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
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
现在,您可以获得
name
的
user
String name = userMap.get("name");
user
本身就是 JsonObject
:
JsonObject user = map.get("user");
好的。首先,JSON 是“JavaScript Object Notation”的缩写,因此您关于“JSON 字符串本质上是一个映射”的断言是不正确的。 JSON 块是一个对象图,使用 JavaScript 语言语法进行描述。由于您试图将对象图强制转换为字符串映射,Sting kay 值对,因此只有在任何给定的 JSON 对象图本质上就是这样的情况下(所以不是很常见),这才有效。更成功的策略可能是
gson.fromJson()
它将您的 JSON 转换为正确的 Java 对象图。