FastJson稍微使用不当就会导致StackOverflow
GitHub 9.4k Star 的Java工程师成神之路 ,不来了解一下吗?
GitHub 9.4k Star 的Java工程师成神之路 ,真的不来了解一下吗?
GitHub 9.4k Star 的Java工程师成神之路 ,真的确定不来了解一下吗?
对于广大的开发人员来说,FastJson大家一定都不陌生。
FastJson(https://github.com/alibaba/fastjson)是阿里巴巴的开源JSON解析库,它可以解析JSON格式的字符串,支持将Java Bean序列化为JSON字符串,也可以从JSON字符串反序列化到JavaBean。
它具有速度快、使用广泛、测试完备以及使用简单等特点。但是,虽然有这么多优点,但是不代表着就可以随便使用,因为如果使用的方式不正确的话,就可能导致StackOverflowError。而StackOverflowError对于程序来说是无疑是一种灾难。
笔者在一次使用FastJson的过程中就遇到了这种情况,后来经过深入源码分析,了解这背后的原理。本文就来从情景再现看是抽丝剥茧,带大家看看坑在哪以及如何避坑。
缘由
FastJson可以帮助开发在Java Bean和JSON字符串之间互相转换,所以是序列化经常使用的一种方式。
有很多时候,我们需要在数据库的某张表中保存一些冗余字段,而这些字段一般会通过JSON字符串的形式保存。比如我们需要在订单表中冗余一些买家的基本信息,如JSON内容:
{ "buyerName":"Hollis", "buyerWechat":"hollischuang", "buyerAgender":"male" }
因为这些字段被冗余下来,必定要有地方需要读取这些字段的值。所以,为了方便使用,一般也对定义一个对应的对象。
这里推荐一个IDEA插件——JsonFormat,可以一键通过JSON字符串生成一个JavaBean。我们得到以下Bean:
public class BuyerInfo { /** * buyerAgender : male * buyerName : Hollis * buyerWechat : hollischuang@qq.com */ private String buyerAgender; private String buyerName; private String buyerWechat; public void setBuyerAgender(String buyerAgender) { this.buyerAgender = buyerAgender;} public void setBuyerName(String buyerName) { this.buyerName = buyerName;} public void setBuyerWechat(String buyerWechat) { this.buyerWechat = buyerWechat;} public String getBuyerAgender() { return buyerAgender;} public String getBuyerName() { return buyerName;} public String getBuyerWechat() { return buyerWechat;} }
然后在代码中,就可以使用FastJson把JSON字符串和Java Bean进行互相转换了。如以下代码:
Order order = orderDao.getOrder(); // 把JSON串转成Java Bean BuyerInfo buyerInfo = JSON.parseObject(order.getAttribute(),BuyerInfo.class); buyerInfo.setBuyerName("Hollis"); // 把Java Bean转成JSON串 order.setAttribute(JSON.toJSONString(buyerInfo)); orderDao.update(order);
有的时候,如果有多个地方都需要这样互相转换,我们会尝试在BuyerInfo中封装一个方法,专门将对象转换成JSON字符串,如:
public class BuyerInfo { public String getJsonString(){ return JSON.toJSONString(this); } }
但是,如果我们定义了这样的方法后,我们再尝试将BuyerInfo转换成JSON字符串的时候就会有问题,如以下测试代码:
public static void main(String[] args) { BuyerInfo buyerInfo = new BuyerInfo(); buyerInfo.setBuyerName("Hollis");