超级灵活的 Java JSON 库

来源:互联网 发布:武汉软件公司 知乎 编辑:程序博客网 时间:2024/06/08 04:21

不是已经有 objectMapper.readValue 了吗?为什么还需要一个新的 JSON 库呢?因为我发现下面这几个场合已有的库无法满足我的需求, 所以发明了 jsoniter (json-iterator):

**和 PHP 打交道**: 如果你要的是 int,他们可能给你 100 也可能给你 "100"。如果你要的是对象,他们在空值的时候可能给你个 []。**处理大量的 JSON**:解析大量的 JSON,但是只是从中提取少量的信息**无法直接绑定到对象上**:JSON自身是 key/value 的形式,和对象模型没法直接绑定上

除了灵活之外 jsoniter 还比现有的库快很多(比如 jackson,gson,fastjson 这些),欢迎第三方来做公正客观的性能评测。这是我自测 1kb json 数据绑定的结果:

jsoniter 的独特之处源自创新:

Any 数据类型:把原始的 byte 数组保存为 Any 对象。只有在用到的时候才会延迟去做解析。而且 Any 还是当成 PHP array 或者 Javascript object 那样来使用,不用关心类型转换问题。Iterator 的抽象:把 JSON 输入流包装为类似 iterator 的对象。你可以用流式解析地方式遍历整个 JSON 里的对象图,就和遍历内存里的集合对象一样方便。类似 gson 的流式 api,但是更简单。Trie-tree:JSON 最大的缺点(也是最强大之处)在于其对象的字段是字符串。数据绑定的时候比较字符串非常耗费时间。jsoniter 使用 tri-tree 的方式来提高性能。灵活的代码生成:所有的 decoder/encoder 的逻辑都可以代码生成。并且提供了反射,动态代码生成和静态代码生成三种方式,Java 的各种平台均可用。只为自己所需的功能付出代价:以 InputStream 作为输入的时候,比 byte[] 要慢。传统的解析器使用继承或者功能开关的方式来做抽象的实现,但是这对于性能来说是有损的。jsoniter 使用动态代码生成来实现 class shadowing,从而实现无损的切换。校验必填字段:主流的 JSON 解析器都没有实现必填字段检查的功能。当你看到一个int是0的时候,不知道是 JSON 里的值是0,还是上游没有把这个字段传过来。jsoniter 使用了 bit 位来跟踪每一个必填字段,效率很高。

虽然做了很多工作来确保 jsoniter 是最快的。但是大部分人其实只要有一个东西能帮他们把事情搞定就好了。来一个例子展示 api 是多么的灵活,也许更有意义:

[1024, {“product_id”: 100, “start”: “beijing”}] [“1025”,
{“product_id”: 101, “start”: “shanghai”}]
// many many more lines

每行是代表一个订单。第一个元素是订单id,第二个元素是订单详情。值得注意之处有以下几点:

行数可能很多,一次性读进来内存压力很大某些行的订单id是 int,某些行的订单id是 string。这在和 PHP 交互的时候经常发生。订单详情有很多字段,手工读取很麻烦,需要对象绑定

只需要 6 行代码,以上所有问题都可以解决:

JsonIterator iter = JsonIterator.parse(input); // input stream
OrderDetails orderDetails = new OrderDetails(); // reused
while(iter.whatIsNext() != ValueType.INVALID) {
Any order = iter.readAny(); // lazy
int orderId = order.toInt(0); // weakly typed
String start = order.get(1).bindTo(orderDetails).start; // data binding }

JsonIterator.parse 以 InputStream 作为输入,所有解析都是流式处理的readAny 返回了 Any 类型的对象。实际的解析只有在取成员字段的时候才发生。用起来简单,而且速度快。bindTo(orderDetails),不仅仅支持对象绑定,甚至可以绑定到已有对象上避免分配内存

jsoniter 在普通的序列化,反序列化的场景下也很好使,就一行。

JsonStream.serialize(new int[]{1,2,3})
JsonIterator.deserialize(“[1,2,3]”, int[].class)

jsoniter 不强迫你使用任何一种风格,可以在数据绑定,流式解析,Any三种风格里自由混搭。虽然文档不多,但还是有一些的。还是觉得文档不够,请告诉我你的需求。

希望能引起大家的一点点兴趣。库还很新,如果有 bug 欢迎提交 bug report 和 pull request 到 json-iterator/java。jsoniter 的 golang 版本会在稍后更新到和 java 版本一样的水平,甚至更好。

具体请看
链接:https://zhuanlan.zhihu.com/p/24699465

0 0
原创粉丝点击