深入剖析构建JSON字符串的三种方式(推荐)
前言:JSON是轻量级的数据交换格式,很常用,尤其是在使用埃阿斯时,在后台将数据封装为JSON字符串更是常见。之前在做项目的时候用过几种方式在后端将数组或目录集合转换为JSON字符串,现在回想起来竟然又有些遗忘。现在来一个汇总,把这几种构建JSON字符串的方式彻底回忆起来。
笔记中提供了大量的代码示例,需要说明的是,大部分代码示例都是本人所敲代码并进行测试,不足之处,请大家指正~
一、阿里巴巴的Fastjson
1.Fastjson是一个以爪哇语言编写的JSON处理器,由阿里巴巴公司开发,功能强大。
要使用第三方的工具当然要导入冲突包了,只需导入fastjson-1.2.8.jar即可,罐子包的获取,大家可以直接去网上下载,也可以联系本人。
先来一个fastjson的简单实例吧,如下代码构造了一个顾客的实例,并将此实例转化成为JSON字符串,调用了com.alibaba.fastjson.JSON的toJSONString()方法,将顾客实例传入
@ Testpublic void test1(){ Customer Customer=new Customer();顾客。setid(1);顾客。setcustname(' Tom ');顾客。setaddress(' BEIjing ');字符串jsonStr=JSON。tojsonstring(客户);系统。出去。println(JSonStr);}打印结果:{'address':'BeiJing ',' custName':'Tom ',' id':1}
再来一个小测试,将一个目录的顾客的集合转换为JSON字符串,22 行还是直接调用JSON的toJSONString()方法,将目录集合传入即可
/*** 将目录集合转换为JSON字符串*/@ Testpublic void test2(){ LiST customer LiST=new ArrayList();客户客户=新客户();顾客。setid(1);顾客。setcustname(' Tom ');顾客。setaddress(' BEIjing ');lists.add(客户);客户客户2=新客户();顾客2。SetID(1);顾客2。setcustname(' Bob ');顾客2。setaddress(' ShanghaI ');名单。添加(客户2);字符串jsonStr=JSON。tojsonstring(列表);系统。出去。println(JSonStr);}打印结果:[{'address':'BeiJing ',' custName':'Tom ',' id':1},{'address':'ShangHai ',' custName':'Bob ',' id':1}]
2.深入研究一下,我们看下面这种情况:3 行创建了一个目录的顾客集合,10 和11 行进行了一个重复的增加操作,那么打印结果是什么样的呢?
@ Testpublic void test3(){ list customer list=new ArrayList();客户客户=新客户();顾客。setid(1);顾客。setcustname(' Tom ');顾客。setaddress(' BEIjing ');lists.add(客户);lists.add(客户);字符串jsonStr=JSON。tojsonstring(列表);系统。出去。println(JSonStr);}打印结果:[{'address':'BeiJing ',' custName':'Tom ',' id':1},{'$ref':'$[0]'}],大家看,第二个顾客实例没有打印出,这就证明了fastjson默认禁止循环的引用,如果想改变这种情况,需要在JSON的toJSONString()方法中传递第二个参数序列化功能禁用循环引用保护即可解决,如下:
@ Testpublic void test3(){ list customer list=new ArrayList();客户客户=新客户();顾客。setid(1);顾客。setcustname(' Tom ');顾客。setaddress(' BEIjing ');lists.add(客户);lists.add(客户);字符串jsonStr=JSON。TojsonString(列表,序列化功能.disablecirculareferencedetect);系统。出去。println(JSonStr);}此时的打印结果为:[{'address':'BeiJing ',' custName':'Tom ',' id':1},{'address':'BeiJing ',' custName':'Tom ',' id':1}],建议以后再使用JSON的toJSONString()方法时将第二个参数添加上
3.再深入一点,来看一个常见的问题,部门和经理类维护双向一对一的关联关系,部门类中有经理类的引用经理类中有部门类的引用,来看如下代码:在11 和12 行设置了关联关系,14 行和15 行进行JSON字符串的转换,结果会怎样呢?
@ Test public void test4(){ Manager mgr=new Manager();经理。setmgrid(1);经理。setmgrname(' Tom ');部门部门=新部门();setdeptid部门(2);dept . setdeptname(' DEV ');经理(部门);dept.setManager(经理);字符串jsonStr=JSON。to sonstring(dept,SerializerFeature .disablecirculareferencedetect);//String jsonStr=JSON。tojsonstring(mgr,SerializerFeature ).disablecirculareferencedetect);系统。出去。println(JSonStr);}答案是,抛出了异常,常见的java.lang.StackOverflowError,抛异常的原因是双方都维护关联关系进入了死循环,那么如何解决这个问题呢?可以在一方添加@JSONField(serialize=false)注解,7 行所示,即可解决
公共类部门{私有整数deptId私有字符串deptName @ JSONField(serialize=false)私有经理管理器;public Integer getDeptId(){ return deptId;} public void setDeptId(Integer deptId){ this。deptId=deptId} public String getDeptName(){ return deptName;} public void setDeptName(String deptName){ this。deptName=deptName} public Manager getManager(){ return Manager;} public void setManager(Manager Manager Manager){ this。经理=经理;} }打印结果为:{'dept':{'deptId':2,' deptName':'DEV'},' mgrId':1,' mgrName':'Tom'},结果也很令人满意。
4.最后提供一个fastjson的工具类,开发时可以直接使用,供大家参考
包契。嘘。utils导入Java。io。ioexception导入Java。乌提尔。日期;导入Java。乌提尔。HashMap导入Java。乌提尔。地图;导入javax。servlet。http。HttpServletResponse进口。com。阿里巴巴。法斯森。JSON进口。com。阿里巴巴。法斯森。序列化程序。序列化程序功能;公共类FastJsonUtil { /** *将对象转成json串* @param对象* @将*/public静态字符串返回给sonstring(对象对象){//disablecirculareferencedetect来禁止循环引用检测返回JSON.toJSONString(对象,序列化功能.disablecirculareferencedetect);} //输出json公共静态void write _ JSON(HttpServletresponse响应,String jsonString){ response。setContentType(' application/JSON;utf-8 ');回应。setcharacter encoding(' UTF-8 ');请尝试{ response.getWriter().print(JSonString);} catch (IOException e) { //TODO自动生成的捕捉块e . print stack trace();} } /** * ajax提交后回调的json字符串* @返回*/public静态String Ajax结果(布尔成功,字符串消息){ Map Map=new HashMap();地图。'放('成功,成功);//是否成功map.put('message ',message);//文本消息字符串JSON=JSON。TojsonString(地图);返回json} /** * JSON串自动加前缀* @param json原json字符串* @param前缀前缀* @返回加前缀后的字符串*/public static String jsonformateradprefix(String JSON,String前缀,MapString,Object new map){ if(new map==null){ new map=new HashMap();}映射字符串,对象映射=(映射)JSON。解析(JSON);对于(字符串键:映射。键集()){对象对象=映射。get(key);if(isEntity(object)){ String jsonString=JSON。到jsonString(对象);jsonformateradprefix(jsonString,前缀键"."),新地图);}else{ newmap.put(前缀键,对象);} }返回JSON。TojsonString(新地图);} /** * 判断某对象是不是实体* @param对象* @return */private静态布尔等熵(对象对象){ if(字符串的对象实例){ return false}如果(对象整数的实例){返回false}如果(对象实例的龙){返回false} if(Java的对象实例。数学。BigDecimal){返回false}如果(日期的对象实例){ return false } if(Java的对象实例。乌提尔。collection){ return false;}返回真实}}二杰克逊
1.同样也需要导入冲突包杰克逊导入的冲突包有三个
具体使用也通过一个小例子说明:
打包。软件。杰克逊;导入Java。乌提尔。数组;导入Java。乌提尔。列表;进口。com。fasterxml。杰克逊。注释。jsonignore进口。com。fasterxml。杰克逊。核心。jsonprocessingexception导入com。fasterxml。杰克逊。数据绑定。对象映射器;公共类客户{私有int id私有字符串名称;公共客户(int id,String name){ super();this . id=idthis . name=name } public int GetID(){ return id;} public void SetID(int id){ this。id=id} public String getName(){ return name;} public void setName(String name){ this。name=name} public String getCity(){ return ' BeiJing ';} @JsonIgnore公共字符串getSchool(){ 0返回“学校”;}公共静态void main(String[]args)引发JsonProcessingException { //创建对象映射器对象对象映射器=新对象映射器();客户客户=新客户(1,"汤姆");列表客户列表=数组客户,新客户(2,‘鲍勃’);//调用对象映射器的writeValueAsString(xxx)方法,把一个对象或几个传入,转为一个JSON字符串字符串jsonStr=映射器。writevalueasstring(列表);系统。出去。println(JSonStr);}}定义了一个顾客类,38 行和43 行定义了两个额外的得到方法并直接赋值主方法中创建对象映射器的对象,调用其writeValueAsString()方法,传入单个对象或对象的集合,便会返回对应的JSON字符串,打印结果为:[{'id':1,' name':'Tom ',' city':'BeiJing'},{'id':2,' name':'Bob ',' city':'BeiJing'}],大家可能会发现,我们43 行定义的getSchool()方法中的学校没有被打印出,这是因为我们在此方法上添加了@JsonIgnore注解,添加了此注解,在构造JSON字符串时便忽略此属性,细想一下,此注解添加到得到方法上,这也说明杰克逊构造JSON字符串时基于吸气剂方法的。
2.与之前一样,我们想看一看杰克逊有没有禁止循环的引用,类似的代码:
@Test public void test2()引发JsonProcessingException { listscuscustomer list=new ArrayList();客户客户=新客户();顾客。setid(1);顾客。setcustname(' Tom ');顾客。setaddress(' BEIjing ');lists.add(客户);lists.add(客户);对象映射器=新对象映射器();字符串jsonStr=映射器。writevalueasstring(列表);系统。出去。println(JSonStr);}来看一下输出结果:[{'id':1,' custName':'Tom ',' address':'BeiJing'},{'id':1,' custName':'Tom ',' address':'BeiJing'}],结果显而易见。
3.我们再来看一看如果像Fastjson中测试的部门和经理双向一对一映射的例子杰克逊会表现的怎么样:
@Test public void test1()引发JsonProcessingException { Manager mgr=new Manager();经理。setmgrid(1);经理。setmgrname(' Tom ');部门部门=新部门();setdeptid部门(2);dept . setdeptname(' DEV ');经理(部门);dept.setManager(经理);对象映射器=新对象映射器();字符串jsonStr=映射器。writevalueasstring(dept);系统。出去。println(JSonStr);}直接运行还是会出相同的异常由: Java。朗。stackoverflow错误引起,我们的思路与测试Fastjson一样,为部门中的经理引用添加@JsonIgnore注解,异常解决了,但打印结果是很满意,结果为:{'deptId':2,' deptName':'DEV'},远不如Fastjson的输出结果。由此可以看出Fastjson功能之强大。
三、谷歌Gson
1.看看如何使用:罐子包呢只需要一个gson-2.2.4.jar,普通对象与集合转为JSON没有什么可说的,简单演示一下将目录集合转为JSON字符串吧,直接新的出Gson的对象,调用其toJson()方法传入需要转换的对象即可。
@ Test public void test2(){ list customer list=new ArrayList();客户客户=新客户();customer . setid(1);customer . setcustname(' Tom ');customer . setaddress(' BeiJing ');lists.add(客户);客户客户2=新客户();customer 2 . SetID(1);customer 2 . setcustname(' Bob ');customer 2 . setaddress(' ShanghaI ');list . add(customer 2);Gson Gson=new Gson();string jsonStr=gson . to JSON(list);system . out . println(JSonStr);}打印结果:[{'address' :' Beijing ',' custname' :' Tom ',' id' :1},{'address' :' Shanghai ',' custname' :' bob ',' id' : '
2.是否禁止循环引用?
@ Test public void test3(){ list customer list=new ArrayList();客户客户=新客户();customer . setid(1);customer . setcustname(' Tom ');customer . setaddress(' BeiJing ');lists.add(客户);lists.add(客户);Gson Gson=new Gson();string jsonStr=gson . to JSON(list);system . out . println(JSonStr);}输出结果:[{'id' :1,' custname' :' Tom ',' address' :' Beijing'},{'id' :1,' custname' :' Tom ',' address' :' Bei
3.如果存在双向一对一的关系映射,谷歌Gson也会出现无限循环问题,导致java.lang.StackOverflowError异常,但Gson并没有给我们提供说明。为了解决这个问题,LZ提供了一个解决方案。谷歌Gson使用ExclusionStrategy策略序列化某个字段或域,可以通过这个界面自定义一个注释来解决这个问题。但是建议如果涉及双向关系的对象转换为JSON,应该使用Fastjson。
四种或三种方法的简单比较
LZ从以下几个方面比较了三种构造JSON字符串的方式:
1.jar包:显然Fastjson和Google Gson赢了,Jackson需要加入三个jar包。
2.简单对象或集合被转换为JSON:如果把普通的简单物件或收藏品进行转换,杰克逊和谷歌Gson可能会赢一些,至少构造起来更方便。
3.它涉及到双向关系的转换:毫无疑问,阿里巴巴的Fastjson会赢。
建议在实际发展中根据自身需求选择合理的方式。
以上三种深度分析和构造JSON字符串的方法(推荐)都是边肖分享的内容,希望能给大家一个参考和支持。
版权声明:深入剖析构建JSON字符串的三种方式(推荐)是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。