标签(空格分隔): fastjson
最近基于他人项目做二次开发,遇到了循环引用的问题,简单来说A引用了B,B引用了C,C引用了A,那么转换json就会无休止的转换下去.
更复杂的情况,A中引用了B,B中引用了一个A的集合,比如广告引用了广告类型,广告类型里面又有该类型下的所属广告.
这种又叫做双向引用,个人感觉这种设计本身就不是很合理,当然还要看具体使用场景了.
广告类:
/**
* @author Niu Li
* @date 2016/8/12
*/
public class ADEntity {
private int id;
private String name;
//引用了一个广告实体类
private ADTypeEntity adTypeEntity;
public ADEntity(int id, String name, ADTypeEntity adTypeEntity) {
this.id = id;
this.name = name;
this.adTypeEntity = adTypeEntity;
}
//省略get和set
}
广告实体类:
import java.util.List;
/**
* @author Niu Li
* @date 2016/8/12
*/
public class ADTypeEntity {
private int id;
private String name;
//引用了其广告集合
private List lists;
//省略get和set
}
测试代码:
public class TestApp {
public static void main(String[] args) {
//构造广告类型
ADTypeEntity adTypeEntity = new ADTypeEntity();
adTypeEntity.setId(1);
adTypeEntity.setName("轮播图");
//构造广告
ADEntity entity1 = new ADEntity(1,"图1",adTypeEntity);
ADEntity entity2 = new ADEntity(2,"图2",adTypeEntity);
ADEntity entity3 = new ADEntity(3,"图3",adTypeEntity);
List lists = new ArrayList();
lists.add(entity1);
lists.add(entity2);
lists.add(entity3);
//双向引用
adTypeEntity.setLists(lists);
String result = JSON.toJSONString(entity1);
System.out.println(result);
}
}
结果可以看到双向引用被替换成$ref
了:
{
"adTypeEntity": {
"id": 1,
"lists": [
{
"$ref": "$"
},
{
"adTypeEntity": {
"$ref": "$.adTypeEntity"
},
"id": 2,
"name": "图2"
},
{
"adTypeEntity": {
"$ref": "$.adTypeEntity"
},
"id": 3,
"name": "图3"
}
],
"name": "轮播图"
},
"id": 1,
"name": "图1"
}
两种解决办法就是哪里有循环引用,就过滤掉该字段.
@JSONField(serialize = false)
private List lists;
得到结果
{
"adTypeEntity": {
"id": 1,
"name": "轮播图"
},
"id": 1,
"name": "图1"
}
SimplePropertyPreFilter filter = new SimplePropertyPreFilter(ADTypeEntity.class,"id","name");
String result = JSON.toJSONString(entity1,filter);
这表明对于ADTypeEntity类只序列化id和name字段,这样的话就排除掉list集合引用了,得到的结果和上面一样.
转载自:http://www.cnblogs.com/sandyfog/articles/3679804.html
fastjson可以实现一些接口指定过滤属性.过滤本质是fastjson每一次要序列化字段的时候都会经过Apply方法进行判断,只有Apply返回true的时候才会序列化,因此就可以根据属性名来进行自由过滤.
以下实现PropertyPreFilter接口,根据name值来进行排除判定.
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;
import java.util.HashMap;
import java.util.Map;
/**
* @date 2016/8/17
*/
public class ComplexPropertyPreFilter implements PropertyPreFilter {
private Map, String[]> includes = new HashMap<>();
private Map, String[]> excludes = new HashMap<>();
static {
//全局配置关闭循环引用检测
JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
}
public ComplexPropertyPreFilter() {
}
public ComplexPropertyPreFilter(Map, String[]> includes) {
super();
this.includes = includes;
}
public boolean apply(JSONSerializer serializer, Object source, String name) {
//对象为空。直接放行
if (source == null) {
return true;
}
// 获取当前需要序列化的对象的类对象
Class> clazz = source.getClass();
// 无需序列的对象、寻找需要过滤的对象,可以提高查找层级
// 找到不需要的序列化的类型
for (Map.Entry, String[]> item : this.excludes.entrySet()) {
// isAssignableFrom(),用来判断类型间是否有继承关系
if (item.getKey().isAssignableFrom(clazz)) {
String[] strs = item.getValue();
// 该类型下 此 name 值无需序列化
if (isHave(strs, name)) {
return false;
}
}
}
// 需要序列的对象集合为空 表示 全部需要序列化
if (this.includes.isEmpty()) {
return true;
}
// 需要序列的对象
// 找到不需要的序列化的类型
for (Map.Entry, String[]> item : this.includes.entrySet()) {
// isAssignableFrom(),用来判断类型间是否有继承关系
if (item.getKey().isAssignableFrom(clazz)) {
String[] strs = item.getValue();
// 该类型下 此 name 值无需序列化
if (isHave(strs, name)) {
return true;
}
}
}
return false;
}
/*
* 此方法有两个参数,第一个是要查找的字符串数组,第二个是要查找的字符或字符串
*/
public static boolean isHave(String[] strs, String s) {
for (int i = 0; i < strs.length; i++) {
// 循环查找字符串数组中的每个字符串中是否包含所有查找的内容
if (strs[i].equals(s)) {
// 查找到了就返回真,不在继续查询
return true;
}
}
// 没找到返回false
return false;
}
public Map, String[]> getIncludes() {
return includes;
}
public void setIncludes(Map, String[]> includes) {
this.includes = includes;
}
public Map, String[]> getExcludes() {
return excludes;
}
public void setExcludes(Map, String[]> excludes) {
this.excludes = excludes;
}
}
自己代码中用到的过滤
Pageable pageable = new Pageable(page,rows);
Page promotionPages = promotionService.findPage(pageable);
String[] promotionFilters = {"id", "name","title","image","endDate","priceExpression","memberRanks"};
String[] memberFilter = {"id","name"};
String[] pageFilter = {"pageNumber","pageSize","content","total","totalPages"};
Map,String[]> mapFilter = new HashMap<>();
mapFilter.put(Promotion.class,promotionFilters);
mapFilter.put(MemberRank.class,memberFilter);
mapFilter.put(Page.class,pageFilter);
ResultData result = new ResultData.Builder(ResultVo.OK)
.setData(APPJsonUtil.toJsonObject(mapFilter,null,promotionPages))
.builder();
json工具
/**
* 按照指定序列转换为jsonObject,多级过滤
* @param object
* @return
*/
public static JSONObject toJsonObject(Map, String[]> includes,Map, String[]> excludes, Object object){
ComplexPropertyPreFilter filter = new ComplexPropertyPreFilter();
if (excludes != null) {
filter.setExcludes(excludes);
}
if (includes != null) {
filter.setIncludes(includes);
}
String result = JSON.toJSONString(object, filter);
return JSON.parseObject(result);
}