UDN-企业互联网技术人气社区

板块导航

浏览  : 1268
回复  : 0

[讨论交流] 超级灵活的 Java JSON 库

[复制链接]
开花包的头像 楼主
发表于 2017-1-4 15:28:51 | 显示全部楼层 |阅读模式
  不是已经有 objectMapper.readValue 了吗?为什么还需要一个新的 JSON 库呢?因为我发现下面这几个场合已有的库无法满足我的需求, 所以发明了 jsoniter (json-iterator):

  和 PHP 打交道: 如果你要的是 int,他们可能给你 100 也可能给你 "100"。如果你要的是对象,他们在空值的时候可能给你个 []。

  处理大量的 JSON:解析大量的 JSON,但是只是从中提取少量的信息

  无法直接绑定到对象上:JSON自身是 key/value 的形式,和对象模型没法直接绑定上

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


  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 是多么的灵活,也许更有意义:

  1.   [1024, {"product_id": 100, "start": "beijing"}]

  2.   ["1025", {"product_id": 101, "start": "shanghai"}]

  3.   // many many more lines
复制代码


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

  行数可能很多,一次性读进来内存压力很大

  某些行的订单id是 int,某些行的订单id是 string。这在和 PHP 交互的时候经常发生。

  订单详情有很多字段,手工读取很麻烦,需要对象绑定

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

  1.   JsonIterator iter = JsonIterator.parse(input); // input stream

  2.   OrderDetails orderDetails = new OrderDetails(); // reused

  3.   while(iter.whatIsNext() != ValueType.INVALID) {

  4.   Any order = iter.readAny(); // lazy

  5.   int orderId = order.toInt(0); // weakly typed

  6.   String start = order.get(1).bindTo(orderDetails).start; // data binding

  7.   }
复制代码


  JsonIterator.parse 以 InputStream 作为输入,所有解析都是流式处理的

  readAny 返回了 Any 类型的对象。实际的解析只有在取成员字段的时候才发生。用起来简单,而且速度快。

  bindTo(orderDetails),不仅仅支持对象绑定,甚至可以绑定到已有对象上避免分配内存

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

 
  1.  JsonStream.serialize(new int[]{1,2,3})

  2.   JsonIterator.deserialize("[1,2,3]", int[].class)
复制代码


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

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

原文作者:陶文 来源:开发者头条

相关帖子

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关于我们
联系我们
  • 电话:010-86393388
  • 邮件:udn@yonyou.com
  • 地址:北京市海淀区北清路68号
移动客户端下载
关注我们
  • 微信公众号:yonyouudn
  • 扫描右侧二维码关注我们
  • 专注企业互联网的技术社区
版权所有:用友网络科技股份有限公司82041 京ICP备05007539号-11 京公网网备安1101080209224 Powered by Discuz!
快速回复 返回列表 返回顶部