使用fastJson对json字符串进行反序列化时,有几个点须要注意一下:java
如咱们但愿返回的一个json串为json
"name" : "name", "isDeleted" : true, "isEmpty" : 1
下面是咱们的定义的dto对象,经过序列化后能获得咱们预期的结果么?socket
private String name; private boolean isDeleted; private int isEmpty; public BaseDO() { } public String getName() { return name; } public void setName(String name) { this.name = name; } public boolean isDeleted() { return isDeleted; } public void setDeleted(boolean deleted) { isDeleted = deleted; } public int getIsEmpty() { return isEmpty; } public void setIsEmpty(int isEmpty) { this.isEmpty = isEmpty; }
实际上返回的结果与咱们预期的仍是有差异的ide
解决方案:测试
@JSONField(name = "name") private String name; @JSONField(name = "isDeleted") private boolean isDeleted; @JSONField(name = "isEmpty") private int isEmpty;
注意项:ui
反序列化一个类的内部类时,可能会获取意想不到的结果,实例以下:this
// 测试用例 package com.mogu.hui.study.json; import java.util.List; /** * 用于测试json序列化 * Created by yihui on 16/4/22. */ public class JsonHello { private String name; private Hello hello; public JsonHello () { } public String getName() { return name; } public void setName(String name) { this.name = name; } public Hello getHello() { return hello; } public void setHello(String hello, List<String> user) { Hello h = new Hello(); h.setHello(hello); h.setUser(user); this.hello = h; } @Override public String toString() { return "JsonHello{" + "name='" + name + '\'' + ", hello=" + hello + '}'; } private class Hello { String hello; List<String> user; public Hello(){ } public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } public List<String> getUser() { return user; } public void setUser(List<String> user) { this.user = user; } @Override public String toString() { return "Hello{" + "hello='" + hello + '\'' + ", user=" + user + '}'; } } }
测试文件容下:lua
package com.mogu.hui.study.json; import com.alibaba.fastjson.JSON; import org.junit.Test; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import java.util.Arrays; /** * Created by yihui on 16/4/22. */ public class JsonTest { private static Logger logger = LoggerFactory.getLogger(JsonTest.class); @Test public void innerClassTest() { try { JsonHello jsonHello = new JsonHello(); jsonHello.setName("hello"); jsonHello.setHello("innerHello", Arrays.asList("user1", "user2")); String str = JSON.toJSONString(jsonHello); logger.info("Str: {}", str); Object obj = JSON.parseObject(str, JsonHello.class); logger.info("Obj: {}", obj); } catch (Exception e) { logger.info("error: {}", e); } } }
输出结果:debug
17:20:08.863 [main] INFO com.mogu.hui.study.json.JsonTest - Str: {"hello":{"hello":"innerHello","user":["user1","user2"]},"name":"hello"} 17:21:44.425 [main] INFO com.mogu.hui.study.json.JsonTest - Obj: JsonHello{name='hello', hello=null}
从上面的输出能够看出,反序列化对象的时候,出现诡异的事情,JsonHello对象的hello元素变成了 nullcode
那么是如何产生这个问题的呢?
其实也简单,由于内部类,json反序列化的时候,没法获得该类,"hello":{"hello":"innerHello","user":["user1","user2"]}
这个串无法愉快的转换为 Hello
对象
这种问题如何避免?
不要反序列化匿名类,内部类!!!
关于模板类,反序列化的主要问题集中在没法正确的反序列化为咱们预期的对象,特别是目标对象内部嵌套有容器的时候,这种问题就更明显了,测试实例以下:
package com.mogu.hui.study.json; import java.util.List; /** * 用于测试json序列化 * Created by yihui on 16/4/22. */ public class JsonHello<T> { private String name; private List<T> list; public JsonHello () { } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<T> getList() { return list; } public void setList(List<T> list) { this.list = list; } @Override public String toString() { return "JsonHello{" + "name='" + name + '\'' + ", list=" + list + '}'; } } class Hello { String hello; List<String> user; public Hello(){ } public String getHello() { return hello; } public void setHello(String hello) { this.hello = hello; } public List<String> getUser() { return user; } public void setUser(List<String> user) { this.user = user; } @Override public String toString() { return "Hello{" + "hello='" + hello + '\'' + ", user=" + user + '}'; } }
测试类
package com.mogu.hui.study.json; import com.alibaba.fastjson.JSON; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.Arrays; /** * Created by yihui on 16/4/22. */ public class JsonTest { private static Logger logger = LoggerFactory.getLogger(JsonTest.class); @Test public void innerClassTest() { try { JsonHello<Hello> jsonHello = new JsonHello<>(); jsonHello.setName("hello"); Hello hello = new Hello(); hello.setHello("hello1"); hello.setUser(Arrays.asList("user1", "user2")); Hello hello2 = new Hello(); hello2.setHello("hello2"); hello2.setUser(Arrays.asList("world1", "world2")); jsonHello.setList(Arrays.asList(hello, hello2)); String str = JSON.toJSONString(jsonHello); logger.info("Str: {}", str); Object obj = JSON.parseObject(str, JsonHello.class); logger.info("Obj: {}", obj); } catch (Exception e) { logger.info("error: {}", e); } } }
聚焦在反序列化的obj对象上,反序列化的结果,debug结果如附图
咱们但愿转换为 JsonHello<Hello> 的对象格式,而咱们获取到的结果呢? 其内部的list为一个ArrayList对象,list中的元素为 JsonObject
这种问题改如何解决:
利用 TypeReference
@Test public void innerClassTest() { try { JsonHello<Hello> jsonHello = new JsonHello<>(); jsonHello.setName("hello"); Hello hello = new Hello(); hello.setHello("hello1"); hello.setUser(Arrays.asList("user1", "user2")); Hello hello2 = new Hello(); hello2.setHello("hello2"); hello2.setUser(Arrays.asList("world1", "world2")); jsonHello.setList(Arrays.asList(hello, hello2)); String str = JSON.toJSONString(jsonHello); logger.info("Str: {}", str); Object obj = JSON.parseObject(str, JsonHello.class); logger.info("Obj: {}", obj); Object obj2 = JSON.parseObject(str, new TypeReference<JsonHello<Hello>>() { }); logger.info("obj2: {}", obj2); } catch (Exception e) { logger.info("error: {}", e); } }
咱们利用FastJson 的 parseObject(str,typeReference) 来实现反序列化的时候,获得的结果以下,完美!
当序列化的对象中,包含枚举时,反序列化可能得不到你预期的结果,枚举对象变成了一个String对象, 其实和上面的问题同样,须要
package com.mogujie.service.rate.base; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.TypeReference; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * Created by yihui on 16/10/31. */ public class JsonTest { public enum MyDay { YESDAY("SUNDAY"), TODAY("MONDAY"), TOMORROW("TUESDAY"); private String today; MyDay(String today) { this.today = today; } public String getToday() { return today; } @Override public String toString() { return "MyDay{" + "today='" + today + '\'' + '}'; } } class TTT { MyDay myDay; public TTT() { } public TTT(MyDay myDay) { this.myDay = myDay; } @Override public String toString() { return "TTT{" + "myDay=" + myDay + '}'; } } private MyDay getDay() { return MyDay.TODAY; } @Test public void testJson() { String str = JSON.toJSONString(getDay()); System.out.println(str); // 这样反序列化ok MyDay myDay = JSON.parseObject(str, MyDay.class); System.out.println(myDay); List<MyDay> myDayList = new ArrayList<>(); myDayList.add(MyDay.TODAY); myDayList.add(MyDay.TOMORROW); String str2 = JSON.toJSONString(myDayList); System.out.println(str2); // 反序列化失败, 和模板类的问题同样 try { List<MyDay> out = JSON.parseObject(str2, List.class); for (MyDay myDay1 : out) { System.out.println(myDay1); } }catch (Exception e) { e.printStackTrace(); } // 采用这种方式,反序列化ok TypeReference<List<MyDay>> typeReference = new TypeReference<List<MyDay>>(){ }; try { List<MyDay> out = JSON.parseObject(str2, typeReference); for (MyDay myDay1 : out) { System.out.println(myDay1); } }catch (Exception e) { e.printStackTrace(); } System.out.println("------------"); TTT tt = new TTT(MyDay.TODAY); String str3 = JSON.toJSONString(tt); System.out.println(str3); // 直接反序列化异常 try { TTT recover = JSON.parseObject(str3, TTT.class); System.out.println(recover); } catch (Exception e) { e.printStackTrace(); } } }
输出内容
"TODAY" MyDay{today='MONDAY'} ["TODAY","TOMORROW"] java.lang.ClassCastException: java.lang.String cannot be cast to com.mogujie.service.rate.base.JsonTest$MyDay at com.mogujie.service.rate.base.JsonTest.testJson(JsonTest.java:79) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.junit.runner.JUnitCore.run(JUnitCore.java:160) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) MyDay{today='MONDAY'} MyDay{today='TUESDAY'} ------------ {} com.alibaba.fastjson.JSONException: create instance error, class com.mogujie.service.rate.base.JsonTest$TTT at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.createInstance(JavaBeanDeserializer.java:116) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:356) at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.deserialze(JavaBeanDeserializer.java:135) at com.alibaba.fastjson.parser.DefaultJSONParser.parseObject(DefaultJSONParser.java:551) at com.alibaba.fastjson.JSON.parseObject(JSON.java:251) at com.alibaba.fastjson.JSON.parseObject(JSON.java:227) at com.alibaba.fastjson.JSON.parseObject(JSON.java:186) at com.alibaba.fastjson.JSON.parseObject(JSON.java:304) at com.mogujie.service.rate.base.JsonTest.testJson(JsonTest.java:108) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) at org.junit.runners.ParentRunner.run(ParentRunner.java:309) at org.junit.runner.JUnitCore.run(JUnitCore.java:160) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) Caused by: java.lang.NullPointerException at com.alibaba.fastjson.parser.deserializer.JavaBeanDeserializer.createInstance(JavaBeanDeserializer.java:113) ... 29 more Disconnected from the target VM, address: '127.0.0.1:52140', transport: 'socket' Process finished with exit code 0
fastjson序列化的对象中,若存在重复引用的状况,序列化的结果可能不是咱们预期的结果
@Test public void testJson() { BaseDO baseDO = new BaseDO(); baseDO.setName("base"); baseDO.setDeleted(false); baseDO.setIsEmpty(1); List<Object> res = new ArrayList<>(); res.add("hello"); res.add(baseDO); res.add(123); res.add("no"); res.add(baseDO); res.add(10); res.add(baseDO); String str = JSON.toJSONString(res); logger.info("str :{}", str); }
从运行结果能够看出,这里对重复引用,序列化后,给出的是引用标识, 须要避免上面的方法, 能够显示关闭循环引用检测参数
String str2 = JSON.toJSONString(res, SerializerFeature.DisableCircularReferenceDetect);
咱们能够考虑下,为何fastJson默认是采起的上面的方式,而不是关闭那个配置参数?
用上面的方法能够解决重复引用的问题,可是另一种状况呢 ? 下面的代码输出是怎样的
Map<String,Object> map = new HashMap<>(); map.put("map",map); String str = JSON.toJSONString(map); logger.info("str: {}", str); String str_1 = JSON.toJSONString(map, SerializerFeature.DisableCircularReferenceDetect); logger.info("str_1: {}", str_1);
注意