import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class RefFastJson {
public static void main(String[] args) {
// 模拟返回的数据
String str = "{\n" +
" \"code\": 200,\n" +
" \"data\": {\n" +
" \"users\": [\n" +
" {\n" +
" \"name\": \"死灵\",\n" +
" \"sex\": \"男\",\n" +
" \"age\": 18\n" +
" },\n" +
" {\n" +
" \"name\": \"骷髅\",\n" +
" \"sex\": \"男\",\n" +
" \"age\": 20\n" +
" },\n" +
" {\n" +
" \"name\": \"小黑\",\n" +
" \"sex\": \"女\",\n" +
" \"age\": 38\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"msg\": \"操作成功\"\n" +
"}";
// 开始使用 JSONObject 处理数据
JSONObject jsonObject = JSONObject.parseObject(str);
JSONObject data = jsonObject.getJSONObject("data");
String users = data.getString("users");
List<TUser> userList = JSONObject.parseArray(users, TUser.class);
ArrayList<HashMap<String, Object>> list = new ArrayList<>();
// TODO 此为情况1,即 HashMap 创建在循环外面
HashMap<String, Object> hashMap = new HashMap<>();
userList.forEach((user) -> {
// TODO 此为情况2,即 HashMap 创建在循环里面
// HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("name", user.getName());
hashMap.put("sex", user.getSex());
hashMap.put("age", user.getAge());
list.add(hashMap);
});
System.out.println("list---" + list);
System.out.println("处理前---" + JSON.toJSONString(list));
}
}
class TUser {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
输出结果
list---[{sex=女, name=小黑, age=38}, {sex=女, name=小黑, age=38}, {sex=女, name=小黑, age=38}]
处理前---[{"sex":"女","name":"小黑","age":38},{"$ref":"$[0]"},{"$ref":"$[0]"}]
发现
bug1-list 中的元素都是同一个对象
bug2-JSON.toJSONString(list) 输出的是{"$ref":"$[0]"}
先看bug2,这是 fastjson 支持循环引用引起的(因为 list 中的3元素都一样)
看中文文档中:Fastjson 循环引用_w3cschool
提供了两种解决方法
1、全局配置关闭,即创建一个配置类
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.context.annotation.Configuration;
@Configuration
public class FastJsonConfig {
static {
//全局配置关闭 Fastjson 循环引用
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
}
}
注册到 bean 容器后就会生效
2、局部配置关闭
System.out.println("处理后---" + JSON.toJSONString(list, SerializerFeature.DisableCircularReferenceDetect));
其实 bug2 是由 bug1 引起的,这是因为创建 HashMap 是在循环的外面,改成到里面就没有问题了。
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
public class RefFastJson {
public static void main(String[] args) {
// 模拟返回的数据
String str = "{\n" +
" \"code\": 200,\n" +
" \"data\": {\n" +
" \"users\": [\n" +
" {\n" +
" \"name\": \"死灵\",\n" +
" \"sex\": \"男\",\n" +
" \"age\": 18\n" +
" },\n" +
" {\n" +
" \"name\": \"骷髅\",\n" +
" \"sex\": \"男\",\n" +
" \"age\": 20\n" +
" },\n" +
" {\n" +
" \"name\": \"小黑\",\n" +
" \"sex\": \"女\",\n" +
" \"age\": 38\n" +
" }\n" +
" ]\n" +
" },\n" +
" \"msg\": \"操作成功\"\n" +
"}";
// 开始使用 JSONObject 处理数据
JSONObject jsonObject = JSONObject.parseObject(str);
JSONObject data = jsonObject.getJSONObject("data");
String users = data.getString("users");
List<TUser> userList = JSONObject.parseArray(users, TUser.class);
ArrayList<HashMap<String, Object>> list = new ArrayList<>();
// TODO 此为情况1,即 HashMap 创建在循环外面
// HashMap<String, Object> hashMap = new HashMap<>();
userList.forEach((user) -> {
// TODO 此为情况2,即 HashMap 创建在循环里面
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("name", user.getName());
hashMap.put("sex", user.getSex());
hashMap.put("age", user.getAge());
list.add(hashMap);
});
System.out.println("list---" + list);
System.out.println("处理前---" + JSON.toJSONString(list));
System.out.println("处理后---" + JSON.toJSONString(list, SerializerFeature.DisableCircularReferenceDetect));
}
}
class TUser {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
输出结果
list---[{sex=男, name=死灵, age=18}, {sex=男, name=骷髅, age=20}, {sex=女, name=小黑, age=38}]
处理前---[{"sex":"男","name":"死灵","age":18},{"sex":"男","name":"骷髅","age":20},{"sex":"女","name":"小黑","age":38}]
处理后---[{"sex":"男","name":"死灵","age":18},{"sex":"男","name":"骷髅","age":20},{"sex":"女","name":"小黑","age":38}]
可以看到,bug1 改好后 bug2 就不出现了。
所以出现这个 {"$ref":"$[0]"} 建议检查是否在处理循环时,创建对象的时机不对