动态防止某些字段被 Jackson 的 PropertyFilter 序列化
Dynamically prevent certain fields from being serialized with Jackson's PropertyFilter
我需要能够防止对象的某些字段被序列化,主要是基于它们的类型。例如,考虑以下对象:
class MyPojo {
private int myInt;
private boolean myBoolean;
// getters, setters, etc.
}
我希望能够在序列化时不序列化布尔字段(如果它为 false)。或者如果它为零则不序列化 int。基本上,不要根据类型或特定值的任何 属性 序列化任何特定字段。
我知道 JsonSerializers,我用它来部分解决我的问题,但它是 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
文档,将过滤器应用于字段而不是整个 class 是有效的,这会很棒,但我已经尝试过了,但我似乎无法理解上班。
我找到了解决方案,这正是我要找的。秘诀就是方法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 的需要。
我需要能够防止对象的某些字段被序列化,主要是基于它们的类型。例如,考虑以下对象:
class MyPojo {
private int myInt;
private boolean myBoolean;
// getters, setters, etc.
}
我希望能够在序列化时不序列化布尔字段(如果它为 false)。或者如果它为零则不序列化 int。基本上,不要根据类型或特定值的任何 属性 序列化任何特定字段。
我知道 JsonSerializers,我用它来部分解决我的问题,但它是 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
文档,将过滤器应用于字段而不是整个 class 是有效的,这会很棒,但我已经尝试过了,但我似乎无法理解上班。
我找到了解决方案,这正是我要找的。秘诀就是方法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 的需要。