案例:{"xiaoMing":{"courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"},"studentNo":"0001"},"xiaoHua":{"courses":{"$ref":"$.xiaoMing.courses"},"studentNo":"0002"}}
原因:一个对象被重复引用,fastjson默认开启循环引用检查,所以序列化结果会出现($ref. $.),来标注被重复引用的对象。
package cn.com.dl.bean;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Map;
/**
* Created by yanshao on 2021-01-13.
*/
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {
private static final long serialVersionUID = 465467703322405014L;
private String studentNo;
private Map<String,String> courses;
}
异常案例:
直接com.alibaba.fastjson.JSON#toJSONString(java.lang.Object)来序列化
@Test
public void test(){
Map<String,Student> map = new HashMap<>();
Map<String,String> courses = new HashMap<>();
courses.put("English","English");
courses.put("Chinese","English");
courses.put("Mathematics","Mathematics");
Student xiaoMing = Student.builder()
.studentNo("0001")
.courses(courses)
.build();
map.put("xiaoMing",xiaoMing);
Student xiaoHua = Student.builder()
.studentNo("0002")
.courses(courses)
.build();
map.put("xiaoHua",xiaoHua);
System.out.println(JSONObject.toJSONString(map));
}
序列化结果:
{"xiaoMing":{"courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"},"studentNo":"0001"},"xiaoHua":{"courses":{"$ref":"$.xiaoMing.courses"},"studentNo":"0002"}}
解决方案1:关闭fastjson的循环引用检查
@Test
public void test(){
Map<String,Student> map = new HashMap<>();
Map<String,String> courses = new HashMap<>();
courses.put("English","English");
courses.put("Chinese","English");
courses.put("Mathematics","Mathematics");
Student xiaoMing = Student.builder()
.studentNo("0001")
.courses(courses)
.build();
map.put("xiaoMing",xiaoMing);
Student xiaoHua = Student.builder()
.studentNo("0002")
.courses(courses)
.build();
map.put("xiaoHua",xiaoHua);
System.out.println( JSONObject.toJSONString(map,SerializerFeature.DisableCircularReferenceDetect));
}
序列化结果:
{"xiaoMing":{"courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"},"studentNo":"0001"},"xiaoHua":{"courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"},"studentNo":"0002"}}
解决方案2:使用com.google.gson.Gson
@Test
public void test(){
Map<String,Student> map = new HashMap<>();
Map<String,String> courses = new HashMap<>();
courses.put("English","English");
courses.put("Chinese","English");
courses.put("Mathematics","Mathematics");
Student xiaoMing = Student.builder()
.studentNo("0001")
.courses(courses)
.build();
map.put("xiaoMing",xiaoMing);
Student xiaoHua = Student.builder()
.studentNo("0002")
.courses(courses)
.build();
map.put("xiaoHua",xiaoHua);
Gson gson = new Gson();
System.out.println(gson.toJson(map));
// System.out.println("fastjson" + JSONObject.toJSONString(map,SerializerFeature.DisableCircularReferenceDetect));
}
序列化结果:
{"xiaoMing":{"studentNo":"0001","courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"}},"xiaoHua":{"studentNo":"0002","courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"}}}
解决方案3:深拷贝或者新创建对象
@Test
public void test(){
Map<String,Student> map = new HashMap<>();
Map<String,String> courses = new HashMap<>();
courses.put("English","English");
courses.put("Chinese","English");
courses.put("Mathematics","Mathematics");
Student xiaoMing = Student.builder()
.studentNo("0001")
.courses(courses)
.build();
map.put("xiaoMing",xiaoMing);
Student xiaoHua = Student.builder()
.studentNo("0002")
.courses(new HashMap<>(courses))
.build();
map.put("xiaoHua",xiaoHua);
System.out.println(JSONObject.toJSONString(map));
// Gson gson = new Gson();
// System.out.println(gson.toJson(map));
// System.out.println("fastjson" + JSONObject.toJSONString(map,SerializerFeature.DisableCircularReferenceDetect));
}
注意: 对于循环引用,fastjson和gson处理方式不同,fastjson默认开启循环引用检查,而使用gson序列化时,会堆内存溢出;
fastjson:
fastjson{"map,":{"$ref":"@"},"xiaoMing":{"courses":{"English":"English","Chinese":"English","Mathematics":"Mathematics"},"studentNo":"0001"},"xiaoHua":{"courses":{"$ref":"$.xiaoMing.courses"},"studentNo":"0002"}}
gson:
java.lang.StackOverflowError
at java.lang.StringBuffer.append(StringBuffer.java:270)
at java.io.StringWriter.write(StringWriter.java:112)
at com.google.gson.stream.JsonWriter.string(JsonWriter.java:590)