通过《Jackson忽略字段不序列化字段的3种方法》一讲我们知道,JsonIgnore和JsonIgnoreProperties都可以用来忽略掉指定的字段。
这两个注解有个共同点,就是都在添加注解后就指明了需要过滤的字段。如果想要在序列化的时候,才指定需要过滤的字段,那么可以使用JsonFilter注解来实现。
本篇内容基于Jackson 2.11.2版本,马上开始学习吧。
过滤类的字段
为需要过滤字段的类添加JsonFilter注解。
@JsonFilter("myFilter")
public class Animal {
private String name;
private int sex;
private Integer weight;
// 省略getter、setter方法
@Override
public String toString() {
return "Animal [name=" + name + ", sex=" + sex + ", weight=" + weight + "]";
}
}
忽略指定字段
创建一个不序列化sex和weight的过滤器SimpleBeanPropertyFilter,再将这个过滤器和ID为myFilter的注解进行关联,最后将过滤器应用于ObjectMapper。
最终的效果,就是使得被@JsonFilter("myFilter")注解的类,在类对象被序列化时,不序列化sex和weight。
/**
* 忽略指定的字段
*
* @throws JsonProcessingException
*/
@Test
public void filterExclude() throws JsonProcessingException {
Animal animal = new Animal();
animal.setName("sam");
animal.setSex(1);
animal.setWeight(100);
ObjectMapper mapper = new ObjectMapper();
// 创建一个不序列化sex和weight的过滤器
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.serializeAllExcept("sex", "weight");
// 将上面的过滤器和ID为myFilter的注解进行关联
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", filter);
System.out.println(mapper.writer(filters).writeValueAsString(animal));
}
执行结果:
{"name":"sam"}
序列化指定的字段
SimpleBeanPropertyFilter.serializeAllExcept用于排除掉不需要序列化的字段,对应的SimpleBeanPropertyFilter.filterOutAllExcept用于指定需要序列化的字段。前者相当于排除,而后者则是包含。
/**
* 序列化指定的字段
*
* @throws JsonProcessingException
*/
@Test
public void filterInclude() throws JsonProcessingException {
Animal animal = new Animal();
animal.setName("sam");
animal.setSex(1);
animal.setWeight(100);
ObjectMapper mapper = new ObjectMapper();
// 创建一个只序列化sex和weight的过滤器
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("sex", "weight");
// 将上面的过滤器和ID为myFilter的注解进行关联
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", filter);
System.out.println(mapper.writer(filters).writeValueAsString(animal));
}
执行结果
{"sex":1,"weight":100}
过滤对象的字段
如果对一个类声明了JsonFilter注解,那么任何引用到该类的地方都可以使用到该注解。
有时候,我们只是想针对引用该类的字段进行过滤,这种情况可以直接在该字段上面进行注解。
下面为AnimalWithOwner的People类型的字段owner添加JsonFilter注解,实际上是作用于owner对象的字段。
public class AnimalWithOwner {
private String name;
private int sex;
private Integer weight;
@JsonFilter("myFilter")
private People owner;
// 省略setter、getter方法
@Override
public String toString() {
return "AnimalJsonFilterOnField [name=" + name + ", sex=" + sex + ", weight=" + weight + ", owner=" + owner
+ "]";
}
}
public class People {
private String name;
private int age;
// 省略setter、getter方法
@Override
public String toString() {
return "People [name=" + name + ", age=" + age + "]";
}
}
/**
* 作用于某个类型的字段
*
* @throws JsonProcessingException
*/
@Test
public void filterIncludeOnField() throws JsonProcessingException {
AnimalWithOwner animal = new AnimalWithOwner();
animal.setName("sam");
animal.setSex(1);
animal.setWeight(100);
People owner = new People();
owner.setName("fanny");
owner.setAge(26);
animal.setOwner(owner);
ObjectMapper mapper = new ObjectMapper();
SimpleBeanPropertyFilter filter = SimpleBeanPropertyFilter.filterOutAllExcept("name");
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", filter);
System.out.println(mapper.writer(filters).writeValueAsString(animal));
}
执行结果:
{"name":"sam","sex":1,"weight":100,"owner":{"name":"fanny"}}
自定义过滤器
前面在过滤字段的时候,我们使用的是SimpleBeanPropertyFilter.serializeAllExcept和SimpleBeanPropertyFilter.filterOutAllExcept。
这两个方法,实际上是使用了预先定义好的两个过滤器,分别是SerializeExceptFilter和FilterExceptFilter。
当已有的过滤器满足不了需求的时候,可以参考现有的过滤器,通过自定义过滤器来实现。
先创建一个自定义的过滤器类,然后继承SimpleBeanPropertyFilter,实现两个include方法即可。
/**
* 自定义过滤器.
*
*/
public static class CustomExceptFilter extends SimpleBeanPropertyFilter {
@Override
protected boolean include(BeanPropertyWriter writer) {
return filter(writer.getName(), writer.getType());
}
@Override
protected boolean include(PropertyWriter writer) {
return filter(writer.getName(), writer.getType());
}
private boolean filter(String fieldName, JavaType fieldType) {
// System.out.println(fieldName + " " + fieldType.getTypeName() + " " + fieldType.getRawClass());
// 排除以n开头的字段,以及int类型的字段
if (fieldName.startsWith("n") || fieldType.getRawClass() == int.class) {
return false;
}
return true;
}
}
在这个过滤器中,使用到的是字段名和字段类型。通过一个if语句,排除掉以n开头的字段,以及int类型的字段。
返回true表示包含该字段,返回false表示忽略掉该字段。
/**
* 自定义过滤器. 通过继承SimpleBeanPropertyFilter,根据实际需要编写过滤规则.
*
* @throws JsonProcessingException
*/
@Test
public void customFilter() throws JsonProcessingException {
Animal animal = new Animal();
animal.setName("sam");
animal.setSex(1);
animal.setWeight(100);
ObjectMapper mapper = new ObjectMapper();
SimpleBeanPropertyFilter filter = new CustomExceptFilter();
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", filter);
System.out.println(mapper.writer(filters).writeValueAsString(animal));
}
执行结果:
{"weight":100}
以n开头的是name字段,int类型的是sex字段,所以最后只剩下weight需要序列化。
小结
使用JsonIgnore和JsonIgnoreProperties都可以用来忽略掉指定的字段,这种方法简单实用,但不够灵活。
如果需要更灵活,动态的过滤字段时,可以考虑使用JsonFilter注解。
JsonFilter注解的几个优点:
1.在序列化的时候再指定需要过滤的字段; 2.支持通过包含和排除两方式来过滤字段; 3.通过自定义过滤器,实现更加复杂的过滤规则。
参考
https://github.com/FasterXML/jackson (opens in a new tab)
https://www.logicbig.com/tutorials/misc/jackson/json-filter-annotation.html (opens in a new tab)