代码之家  ›  专栏  ›  技术社区  ›  Matthew Olsson

动态防止某些字段被Jackson的PropertyFilter序列化

  •  1
  • Matthew Olsson  · 技术社区  · 6 年前

    我需要能够防止对象的某些字段被序列化,主要是基于它们的类型。例如,考虑以下对象:

    class MyPojo {
        private int myInt;
        private boolean myBoolean;
    
        // getters, setters, etc.
    }
    

    我希望能够在序列化时,如果布尔字段为false,则不序列化它。或者如果int为零,则不序列化它。基本上,不基于任何类型或特定值的属性序列化任何特定字段。

    我知道JSONSerializer,我用它部分解决了我的问题,但它确实是 impossible to choose not to serialize a field in a JsonSerializer .

    我最接近的方法是实现我自己的PropertyFilter,并通过 @JsonFilter :

    public class XmlPropertyFilter implements PropertyFilter {
        @Override
        public void serializeAsField(Object pojo, JsonGenerator gen, SerializerProvider prov, PropertyWriter writer) throws Exception {
            JavaType type = writer.getType();
    
            if (writer instanceof BeanPropertyWriter) {
                BeanPropertyWriter bWriter = (BeanPropertyWriter) writer;
    
                String fieldName = bWriter.getSerializedName().getValue();
                Field f = pojo.getClass().getDeclaredField(fieldName);
                f.setAccessible(true);
                Object value = f.get(pojo);
    
                if (!type.isTypeOrSubTypeOf(int.class) && value != null) {
                    // Serialize everything that isn't an int and doesn't have a null value
                    prov.defaultSerializeField(fieldName, value, gen);
                } else if (type.isTypeOrSubTypeOf(int.class)) {
                    // Only serialize ints if the value isn't 0
                    if (value != 0) prov.defaultSerializeField(fieldName, value, gen);
                }
            }
    
        }
    
        // ...
    }
    

    这正是我想要的,只是它有破坏包装的副作用(例如,序列化列表)。根据 @JsonFilter 在文档中,对一个字段而不是整个类应用过滤器是有效的,这将是非常棒的,但我已经尝试过了,我似乎无法让它工作。

    1 回复  |  直到 6 年前
        1
  •  3
  •   Matthew Olsson    6 年前

    我找到了解决办法,这正是我想要的。秘密在于方法 BeanPropertyWriter#serializeAsOmittedField(Object, JsonGenerator, SerializerProvider) .这正是JsonSerializer内部不可能做到的事情——它完全删除了输出中的字段。

    下面是此DynamicPropertyFilter的一个示例:

    public class DynamicPropertyFilter implements PropertyFilter {
        public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception {
            if (writer instanceof BeanPropertyWriter) {
                BeanPropertyWriter bWriter = (BeanPropertyWriter) writer;
    
                String fieldName = bWriter.getFullName().getSimpleName();
                Field field = pojo.getClass().getDeclaredField(fieldName);
                field.setAccessible(true);
                Object object = field.get(pojo);
    
                if (Double.class.isInstance(object) && (double) object == 0.0) {
                    // Remove all double fields that are equal to 0.0
                    bWriter.serializeAsOmittedField(pojo, jgen, prov);
                    return;
                } else if (Boolean.class.isInstance(object)) {
                    // Change all boolean fields to 1 and 0 instead of true and false
                    prov.defaultSerializeField(fieldName, (boolean) object ? 1 : 0, jgen);
                    return;
                }
            }
    
            // Serialize field as normal if property is not filtered
            writer.serializeAsField(pojo, jgen, prov);
        }
    
        public void serializeAsElement(Object elementValue, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception {
            writer.serializeAsField(elementValue, jgen, prov);
        }
    
        public void depositSchemaProperty(PropertyWriter writer, JsonObjectFormatVisitor objectVisitor, SerializerProvider provider) throws JsonMappingException {
            writer.depositSchemaProperty(objectVisitor, provider);
        }
    
        @Deprecated
        public void depositSchemaProperty(PropertyWriter writer, ObjectNode propertiesNode, SerializerProvider provider) throws JsonMappingException {
            writer.depositSchemaProperty(propertiesNode, provider);
        }
    }
    

    我不仅可以过滤字段(这主要是我想要的),还可以更改它们(如布尔示例所示)。这样就不需要PropertyFilter和JsonSerializer。