FastJson 自定义过滤器 不输出空数组


SerializeFilter是通过编程扩展的方式定制序列化。Fastjson 支持6种 SerializeFilter,用于不同场景的定制序列化。

  • PropertyPreFilter:根据 PropertyName 判断是否序列化

  • PropertyFilter:根据 PropertyName 和 PropertyValue 来判断是否序列化

  • NameFilter:修改 Key,如果需要修改 Key,process 返回值则可

  • ValueFilter:修改 Value

  • BeforeFilter:序列化时在最前添加内容

  • AfterFilter:序列化时在最后添加内容

1、需求

JSON 数据格式如下,需要过滤掉其中 "book" 的 "price" 属性

{
  "store": {
    "book": [
      {
        "category": "reference",
        "author": "Nigel Rees",
        "title": "Sayings of the Century",
        "price": 8.95
      },
      {
        "category": "fiction",
        "author": "Evelyn Waugh",
        "title": "Sword of Honour",
        "price": 12.99
      }
    ],
    "bicycle": {
      "color": "red",
      "price": 19.95
    }
  },
  "expensive": 10
}

2、SimplePropertyPreFilter过滤器

该过滤器由 Fastjson 提供,代码实现:

String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
SimplePropertyPreFilter filter = new SimplePropertyPreFilter();
filter.getExcludes().add("price");
JSONObject jsonObject = JSON.parseObject(json);
String str = JSON.toJSONString(jsonObject, filter);
System.out.println(str);

结果:

{
  "store": {
    "bicycle": {
      "color": "red"
    },
    "book": [
      {
        "author": "Nigel Rees",
        "category": "reference",
        "title": "Sayings of the Century"
      },
      {
        "author": "Evelyn Waugh",
        "category": "fiction",
        "title": "Sword of Honour"
      }
    ]
  },
  "expensive": 10
}

查看 JSON 数据的过滤结果,发现 "bicycle" 中的 "price" 属性也被过滤掉了,不符合需求

3、LevelPropertyPreFilter过滤器

该自定义过滤器实现 PropertyPreFilter 接口,实现根据层级过滤 JSON 数据中的属性
扩展类:

/**
 * 层级属性删除
 * 
 * @author yinjianwei
 * @date 2017年8月24日 下午3:55:19
 *
 */
public class LevelPropertyPreFilter implements PropertyPreFilter {

    private final Class<?> clazz;
    private final Set includes = new HashSet();
    private final Set excludes = new HashSet();
    private int maxLevel = 0;

    public LevelPropertyPreFilter(String... properties) {
        this(null, properties);
    }

    public LevelPropertyPreFilter(Class<?> clazz, String... properties) {
        super();
        this.clazz = clazz;
        for (String item : properties) {
            if (item != null) {
                this.includes.add(item);
            }
        }
    }

    public LevelPropertyPreFilter addExcludes(String... filters) {
        for (int i = 0; i < filters.length; i++) {
            this.getExcludes().add(filters[i]);
        }
        return this;
    }

    public LevelPropertyPreFilter addIncludes(String... filters) {
        for (int i = 0; i < filters.length; i++) {
            this.getIncludes().add(filters[i]);
        }
        return this;
    }

    public boolean apply(JSONSerializer serializer, Object source, String name) {
        if (source == null) {
            return true;
        }

        if (clazz != null && !clazz.isInstance(source)) {
            return true;
        }

        // 过滤带层级属性(store.book.price)
        SerialContext serialContext = serializer.getContext();
        String levelName = serialContext.toString();
        levelName = levelName + "." + name;
        levelName = levelName.replace("$.", "");
        levelName = levelName.replaceAll("\\[\\d+\\]", "");
        if (this.excludes.contains(levelName)) {
            return false;
        }

        if (maxLevel > 0) {
            int level = 0;
            SerialContext context = serializer.getContext();
            while (context != null) {
                level++;
                if (level > maxLevel) {
                    return false;
                }
                context = context.parent;
            }
        }

        if (includes.size() == 0 || includes.contains(name)) {
            return true;
        }

        return false;
    }

    public int getMaxLevel() {
        return maxLevel;
    }

    public void setMaxLevel(int maxLevel) {
        this.maxLevel = maxLevel;
    }

    public Class<?> getClazz() {
        return clazz;
    }

    public Set getIncludes() {
        return includes;
    }

    public Set getExcludes() {
        return excludes;
    }
}

代码实现:

public static void main(String[] args) {
    String json = "{\"store\":{\"book\":[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}],\"bicycle\":{\"color\":\"red\",\"price\":19.95}},\"expensive\":10}";
    JSONObject jsonObj = JSON.parseObject(json);
    LevelPropertyPreFilter propertyPreFilter = new LevelPropertyPreFilter();
    propertyPreFilter.addExcludes("store.book.price");
    String json2 = JSON.toJSONString(jsonObj, propertyPreFilter);
    System.out.println(json2);
}

结果:

{
  "store": {
    "bicycle": {
      "color": "red",
      "price": 19.95
    },
    "book": [
      {
        "author": "Nigel Rees",
        "category": "reference",
        "title": "Sayings of the Century"
      },
      {
        "author": "Evelyn Waugh",
        "category": "fiction",
        "title": "Sword of Honour"
      }
    ]
  },
  "expensive": 10
}

查看 JSON 数据的过滤结果,实现了上面的需求

4、不输出空数组

在我们平时开发过程中,Java bean 转JSON的时候有一些空数组,导致转换后的多了很多 “无用” 的数据

{

  student:{

  "name":"江南也少",

  "score": []

  }

}

这个时候我们希望这个没有参加考试,也没有分的同学,不用输出score,该怎么办呢?

我们可以定义一个Filter类

public class NotWriteEmptyList implement{

            @Override
            public boolean apply(Object o, String key, Object value) {
                if (value == null) {
                    return false;
                }
                if(value instanceof  String && ((String) value).isEmpty()){
                    return false;
                }
                if(value instanceof List && ((List) value).size() == 0){
                    return  false;
                }
                return true;
            }
       
}
在我们同String的时候new 一个Filter 传进去就OK了

JSON.toJSONString(entity, new NotWriteEmptyList());

这样就会得到如下的结果:

{

  student:{

  "name":"江南也少"

  }

}

参考:https://segmentfault.com/a/1190000010859580

           https://www.cnblogs.com/sandyyeh/p/13942685.html