Snack3-基于Java开发的一个支持 JSONPath 的 JSON 框架,小巧且功能强大,重点是快
推荐背景
在使用Java开发 Fizz网关 的服务编排功能时,要对JSON数据进行序列化和反序列化,还要对JSON数据进行结构调整、字段裁剪、字段映射等,所有这些操作都要基于JSONPATH进行,我们最初使用的是 https://github.com/json-path/JsonPath 但数据处理速度比较慢,达不到我们的要求,正准备要手撕一个JSONPATH解析器时让我发现了Snack3这个Java开发且支持 JSONPath 的 JSON 框架,简直是为我们量身打造的,功能丰富,重要的是快!
Snack3介绍
一个微型JSON + Jsonpath框架,官网: https:// github.com/noear/snack3
基于jdk8,80kb。支持:序列化反序列化、解析和转换、Json path 查询。
<dependency>
<groupId>org.noear</groupId>
<artifactId>snack3</artifactId>
<version>3.2.22</version>
</dependency>
Snack3 借鉴了
Javascript
所有变量由
var
申明,及
Xml dom
一切都是
Node
的设计。其下一切数据都以
ONode
表示,
ONode
也即
One node
之意,代表任何类型,也可以转换为任何类型。
- 强调文档树的操控和构建能力
- 做为中间媒体,方便不同格式互转
-
高性能
Json path
查询(兼容性和性能很赞) -
支持
序列化、反序列化
- 基于 无参构造函数 + 字段 操作实现(因注入而触发动作的风险,不会有)
随便放几个示例
//demo0::字符串化
String json = ONode.stringify(user);
//demo1::序列化
// -- 输出带@type
String json = ONode.serialize(user);
//demo2::反序列化
// -- json 有已带@type
UserModel user = ONode.deserialize(json);
// -- json 可以不带@type (clz 申明了)
UserModel user = ONode.deserialize(json, UserModel.class);
// -- json 可以不带@type,泛型方式输出(类型是已知的)
List<UserModel> list = ONode.deserialize(json, (new ArrayList<UserModel>(){}).getClass());
//demo3::转为ONode
ONode o = ONode.loadStr(json); //将json String 转为 ONode
ONode o = ONode.loadObj(user); //将java Object 转为 ONode
//demo3.1::转为ONode,取子节点进行序列化
ONode o = ONode.loadStr(json);
UserModel user = o.get("user").toObject(UserModel.class);
//demo4:构建json数据(极光推送的rest api调用)
public static void push(Collection<String> alias_ary, String text) {
ONode data = new ONode().build((d)->{
d.getOrNew("platform").val("all");
d.getOrNew("audience").getOrNew("alias").addAll(alias_ary);
d.getOrNew("options")
.set("apns_production",false);
d.getOrNew("notification").build(n->{
n.getOrNew("ios")
.set("alert",text)
.set("badge",0)
.set("sound","happy");
String message = data.toJson();
String author = Base64Util.encode(appKey+":"+masterSecret);
Map<String,String> headers = new HashMap<>();
headers.put("Content-Type","application/json");
headers.put("Authorization","Basic "+author);
HttpUtil.postString(apiUrl, message, headers);
//demo5:取值
o.get("name").getString();
o.get("num").getInt();
o.get("list").get(0).get("lev").getInt();
//demo5.1::取值并转换
UserModel user = o.get("user").toObject(UserModel.class); //取user节点,并转为UserModel
//demo5.2::取值或新建并填充
o.getOrNew("list2").fill("[1,2,3,4,5,5,6]");
//demo6::json path //不确定返回数量的,者会返回array类型
//找到所有的187开头的手机号,改为186,最后输出修改后的json
o.select("$..mobile[?(@ =~ /^187/)]").forEach(n->n.val("186")).toJson();
//找到data.list[1]下的的mobile字段,并转为long
o.select("$.data.list[1].mobile").getLong();
//查找所有手机号,并转为List<String>
List<String> list = o.select("$..mobile").toObject(List.class);
//查询data.list下的所有mobile,并转为List<String>
List<String> list = o.select("$.data.list[*].mobile").toObject(List.class);
//找到187手机号的用户,并输出List<UserModel>
List<UserModel> list = o.select("$.data.list[?(@.mobile =~ /^187/)]")
.toObjectList(UserModel.class);
List<UserModel> list = o.select("$.data.list[?(@.mobile =~ /^187/)]")
.toObjectList(UserModel.class);
//demo7:遍历
//如果是个Object
o.forEach((k,v)->{
//...
//如果是个Array
o.forEach((v)->{
//...
//demo8:自定义编码
Options options = Options.def();
options.addEncoder(Date.class, (data, node) -> {
node.val().setString(DateUtil.format(data, "yyyy-MM-dd"));