鮮為人知的 jackson Pointer 語法,超好用!
一、語法
JSON Pointer 是一個(gè)包含零個(gè)或多個(gè)引用標(biāo)記的 Unicode 字符串,每個(gè)引用標(biāo)記以 “/” (%x2F) 字符為前綴。如果引用標(biāo)記包含 “~” (%x7E) 或 “/” (%x2F) 字符,則它們必須分別被編碼為 “~0” 和 “~1”。它的 ABNF 語法如下:
json-pointer = *( "/" reference-token )
reference-token = *( unescaped / escaped )
unescaped = %x00-2E / %x30-7D / %x7F-10FFFF
escaped = "~" ( "0" / "1" )
如果一個(gè) JSON 指針值不符合這個(gè)語法,則屬于錯(cuò)誤的條件。
二、語法示例
JSON Pointer 語法所有引號(hào)“"” (%x22)、反斜杠“\” (%x5C)和控制字符(%x00-1F)的實(shí)例必須被轉(zhuǎn)義。例如,給定以下JSON文檔
{
"foo": ["bar", "baz"],
"": 0,
"a/b": 1,
"c%d": 2,
"e^f": 3,
"g|h": 4,
"i\\j": 5,
"k\"l": 6,
" ": 7,
"m~n": 8
}
那么以下 JSON 字符串應(yīng)用標(biāo)記和對(duì)應(yīng)的值:
"" // 讀取整個(gè)文檔
"/foo" ["bar", "baz"]
"/foo/0" "bar" // 讀取數(shù)組、集合中的第0個(gè)元素
"/" 0
"/a~1b" 1
"/c%d" 2
"/e^f" 3
"/g|h" 4
"/i\\j" 5
"/k\"l" 6
"/ " 7
"/m~0n" 8
三、復(fù)雜 Json 示例
示例 json 文本(節(jié)選自筆者掘金用戶信息):
{
"err_no": 0,
"err_msg": "success",
"data": {
"user_name": "如夢(mèng)技術(shù)",
"description": "生活不止眼前的茍且,還有詩和遠(yuǎn)方的田野。",
"blog_address": "https://www.dreamlu.net",
"user_growth_info": {
"user_id": 1591748566975837,
"jpower": 4056,
"jscore": 1208.1,
"jpower_level": 4,
"jscore_level": 5,
"jscore_title": "先鋒掘友",
"author_achievement_list": [],
"vip_level": 1,
"vip_title": "初學(xué)乍練",
"jscore_next_level_score": 2000,
"jscore_this_level_mini_score": 500,
"vip_score": 0
}
}
}
需求是只需要獲取 “jscore_title” 字段,獲取這個(gè)值按照上文的語法我們的完整引用標(biāo)記為:/data/user_growth_info/jscore_title。筆者采用 mica 中的 mica-core 中的 Jsonutil作為 jackson 的輔助工具類(這應(yīng)該也是市面上最好用和最全的一個(gè) jackson json 工具類)。示例 java 代碼:
// 讀取 json 為 JsonNode
JsonNode jsonNode = JsonUtil.readTree(json);
// 調(diào)用 at 方法,傳入 JSON Pointer 引用標(biāo)記
JsonNode titleNode = jsonNode.at("/data/user_growth_info/jscore_title");
// 讀取節(jié)點(diǎn)文本
String jsCoreTitle = titleNode.asText();
System.out.println(jsCoreTitle); // 先鋒掘友
注意:使用 JSON Pointer 語法獲取不存在的節(jié)點(diǎn)時(shí)也不會(huì)報(bào)錯(cuò),在使用 asText、asInt 等方法獲取節(jié)點(diǎn)的值時(shí)會(huì)默認(rèn)返回 null,當(dāng)然這些方法也都有個(gè)帶默認(rèn)值的方法,非常好用。另外我們也可以將某個(gè)節(jié)點(diǎn)轉(zhuǎn)換成 Java Bean,例如上面的 user_growth_info節(jié)點(diǎn),示例代碼如下:UserGrowthInfo Bean(使用 idea GsonFormatPlus 插件生成)
@Data
public class UserGrowthInfo {
@JsonProperty("user_id")
private Long userId;
@JsonProperty("jpower")
private Integer jpower;
@JsonProperty("jscore")
private Double jscore;
@JsonProperty("jpower_level")
private Integer jpowerLevel;
@JsonProperty("jscore_level")
private Integer jscoreLevel;
@JsonProperty("jscore_title")
private String jscoreTitle;
@JsonProperty("author_achievement_list")
private List<?> authorAchievementList;
@JsonProperty("vip_level")
private Integer vipLevel;
@JsonProperty("vip_title")
private String vipTitle;
@JsonProperty("jscore_next_level_score")
private Integer jscoreNextLevelScore;
@JsonProperty("jscore_this_level_mini_score")
private Integer jscoreThisLevelMiniScore;
@JsonProperty("vip_score")
private Integer vipScore;
}
讀取 json 并轉(zhuǎn)換成 UserGrowthInfo Bean:
// 讀取 json 為 JsonNode
JsonNode jsonNode = JsonUtil.readTree(json);
// 讀取 user_growth_info 節(jié)點(diǎn)
JsonNode userGrowthInfoNode = jsonNode.at("/data/user_growth_info");
// 轉(zhuǎn)換成 UserGrowthInfo bean
UserGrowthInfo userGrowthInfo = JsonUtil.treeToValue(userGrowthInfoNode, UserGrowthInfo.class);
System.out.println(userGrowthInfo);
// 輸出結(jié)果:UserGrowthInfo(userId=1591748566975837, jpower=4056, jscore=1208.1, jpowerLevel=4,
// jscoreLevel=5, jscoreTitle=先鋒掘友, authorAchievementList=[], vipLevel=1, vipTitle=初學(xué)乍練,
// jscoreNextLevelScore=2000, jscoreThisLevelMiniScore=500, vipScore=0)
四、總結(jié)
Jackson JSON Pointer 語法非常簡單易用,Jackson 官網(wǎng)文檔改版之后這個(gè)文檔很難找到了。筆者從14年開始使用,并且將她融入到很多 mica 組建中。例如使用 mica-http 來讀取我們想要的結(jié)果:
// 讀取 linkedin 郵箱
private String getUserEmail(String accessToken) {
return HttpRequest.get("https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))")
.addHeader("Host", "api.linkedin.com")
.addHeader("Connection", "Keep-Alive")
.addHeader("Authorization", "Bearer " + accessToken)
.execute()
.asJsonNode()
.at("/elements/0/handle~0/emailAddress")
.asText();
}
Jackson 還是非常好用的,希望此篇文章對(duì)大家有所幫助!更多精彩好文敬請(qǐng)關(guān)注我們?。?!