如何基于带有注释的排除进行动态过滤?

时间:2019-01-07 10:57:43

标签: java jackson objectmapper

我想开发一个组件,该组件允许根据要序列化的对象的字段的排除算法(JSON)筛选DTO的字段。基于杰克逊注释“ @JsonProperty”中提到的名称(如果存在的话),否则使用字段本身的名称(映射不带注释)。

请问,如何基于带有注释的排除进行动态过滤?有一些有用的资源(代码,tuto等)吗?

JacksonFieldFilter类

public class JacksonFieldFilter {

    public <T> T filter(T input, List<String> toExclude, Function<Object, Object> fun) throws IllegalArgumentException, IllegalAccessException {

        Field[] fields = input.getClass().getFields();
        for (Field field : fields) {

            // check is not elementary type.
            // if not ==> get its annotation
            Annotation[] annaotations = field.getAnnotations();

            /// Filter on Jakson annotation only with name == JSonProperty
            Annotation ja = getJakson(annaotations);

            /// get annotation value as String ==> annotationNameValue.
            String annotationNameValue = null;

            if (toExclude.contains(annotationNameValue)) {
                /// found the name in excluded values list
                Object prev = field.get(input);
                field.set(input, fun.apply(prev));
            }

        }

        return input;
    }

    Annotation getJakson(Annotation[] annaotations) {
        for (Annotation annotation : annaotations) {
            if (annotation.annotationType().isAssignableFrom(JsonProperty.class)) {
                return annotation;
            }
        }
        return null;
    }

    // Test 

    public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException {
        JacksonFieldFilter filter = new JacksonFieldFilter();
        Item item = new Item();
        item.setField1("London");
        item.setField2("Paris");

        Item clone = null; // item.

        clone = filter.filter(clone, Arrays.asList(new String[] { "field_1" }), p -> {
            System.err.println("Erasing " + p);
            return null;
        });

        // OUTPUT ==> {"field_2":"Paris"}
        System.out.println(clone); 
    }

}

类项目

public class Item {
    @JsonProperty("field_1")
    private String field1;
    @JsonProperty("field_2")
    private String field2;

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public String getField2() {
        return field2;
    }

    public void setField2(String field2) {
        this.field2 = field2;
    }

}

1 个答案:

答案 0 :(得分:0)

您的代码有一些问题:

  • 您没有将item对象传递给过滤器函数,因此无法复制clone中的字段值
  • Item类中的字段是私有的,因此您必须使用getClass().getDeclaredFields()setAccessible()来访问/写入它们。

请尝试以下代码:

public static class JacksonFieldFilter {

    public <T> T filter(T src, T dest, Collection<String> toExclude, Function<String, Void> callback)
        throws IllegalArgumentException, IllegalAccessException {

        Field[] fields = src.getClass().getDeclaredFields();
        for (Field field : fields) {
            JsonProperty property = field.getAnnotation(JsonProperty.class);
            if (property != null) {
                String value = property.value();
                if (toExclude.contains(value)) {
                    callback.apply(value);
                } else {
                    // Write the value from "src" to "dest"
                    field.setAccessible(true); // Without this we can not write into a private field
                    field.set(dest, field.get(src));
                }
            }
        }
        return dest;
    }
}

// ...
public static void main(String[] args) throws Exception {
    Item item = new Item();
    item.setField1("London");
    item.setField2("Paris");

    Item clone = new JacksonFieldFilter().filter(item, new Item(), Arrays.asList(new String[]{"field_1"}), (f) -> {
        System.out.println("Erasing " + f);
        return null;
    });
    System.out.println(clone);
}

输出:

Erasing field_1
Item{field1=null, field2=Paris}