Jackson使用JsonFilter注解过滤字段

通过《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.通过自定义过滤器,实现更加复杂的过滤规则。

参考

《轻松学习Jackson》程序员口袋里的开发手册

https://github.com/FasterXML/jackson

https://www.logicbig.com/tutorials/misc/jackson/json-filter-annotation.html


---转载本站文章请注明作者和出处 996极客教程(996geek.com),请勿用于任何商业用途---

留下评论