Jackson 仅序列化符合自定义标准的字段
Contents
1. 概述
本教程将说明我们如何使用 Jackson 仅在满足特定的自定义条件时才序列化字段。 例如,假设我们只想序列化一个整数值,如果它是正数——如果不是,我们想完全跳过它。
2. 使用Jackson过滤器控制序列化过程
首先,我们需要在实体上定义过滤器,使用*@JsonFilter*注解:
@JsonFilter("myFilter")
public class MyDto {
private int intValue;
public MyDto() {
super();
}
public int getIntValue() {
return intValue;
}
public void setIntValue(int intValue) {
this.intValue = intValue;
}
}
然后,我们需要定义我们的自定义PropertyFilter:
PropertyFilter theFilter = new SimpleBeanPropertyFilter() {
@Override
public void serializeAsField
(Object pojo, JsonGenerator jgen, SerializerProvider provider, PropertyWriter writer)
throws Exception {
if (include(writer)) {
if (!writer.getName().equals("intValue")) {
writer.serializeAsField(pojo, jgen, provider);
return;
}
int intValue = ((MyDtoWithFilter) pojo).getIntValue();
if (intValue >= 0) {
writer.serializeAsField(pojo, jgen, provider);
}
} else if (!jgen.canOmitFields()) { // since 2.3
writer.serializeAsOmittedField(pojo, jgen, provider);
}
}
@Override
protected boolean include(BeanPropertyWriter writer) {
return true;
}
@Override
protected boolean include(PropertyWriter writer) {
return true;
}
};
此过滤器包含实际逻辑,根据其值决定是否要序列化intValue字段。
接下来,我们将此过滤器挂钩到ObjectMapper并序列化一个实体:
FilterProvider filters = new SimpleFilterProvider().addFilter("myFilter", theFilter);
MyDto dtoObject = new MyDto();
dtoObject.setIntValue(-1);
ObjectMapper mapper = new ObjectMapper();
String dtoAsString = mapper.writer(filters).writeValueAsString(dtoObject);
最后,我们可以检查intValue字段确实不是编组 JSON 输出的一部分:
assertThat(dtoAsString, not(containsString("intValue")));
3. 有条件地跳过对象
现在 - 让我们讨论如何在基于属性值进行序列化时跳过对象。我们将跳过属性hidden为true的所有对象:
3.1. 可隐藏的类
首先,我们来看看我们的Hidable Interface:
@JsonIgnoreProperties("hidden")
public interface Hidable {
boolean isHidden();
}
我们有两个简单的类实现这个接口Person,Address: Person类:
public class Person implements Hidable {
private String name;
private Address address;
private boolean hidden;
}
和Address类:
public class Address implements Hidable {
private String city;
private String country;
private boolean hidden;
}
注意:我们使用*@JsonIgnoreProperties(“hidden”)来确保hidden*属性本身不包含在 JSON 中
3.2. 自定义序列化器
接下来——这是我们的自定义序列化程序:
public class HidableSerializer extends JsonSerializer<Hidable> {
private JsonSerializer<Object> defaultSerializer;
public HidableSerializer(JsonSerializer<Object> serializer) {
defaultSerializer = serializer;
}
@Override
public void serialize(Hidable value, JsonGenerator jgen, SerializerProvider provider)
throws IOException, JsonProcessingException {
if (value.isHidden())
return;
defaultSerializer.serialize(value, jgen, provider);
}
@Override
public boolean isEmpty(SerializerProvider provider, Hidable value) {
return (value == null || value.isHidden());
}
}
注意:
- 当对象不会被跳过时,我们将序列化委托给默认注入的序列化程序。
- 我们重写了*isEmpty()*方法——以确保在 Hidable 对象是属性的情况下,属性名称也从 JSON 中排除。
3.3. 使用BeanSerializerModifier
最后,我们需要使用BeanSerializerModifier在自定义的HidableSerializer中注入默认的序列化器——如下:
ObjectMapper mapper = new ObjectMapper();
mapper.setSerializationInclusion(Include.NON_EMPTY);
mapper.registerModule(new SimpleModule() {
@Override
public void setupModule(SetupContext context) {
super.setupModule(context);
context.addBeanSerializerModifier(new BeanSerializerModifier() {
@Override
public JsonSerializer<?> modifySerializer(
SerializationConfig config, BeanDescription desc, JsonSerializer<?> serializer) {
if (Hidable.class.isAssignableFrom(desc.getBeanClass())) {
return new HidableSerializer((JsonSerializer<Object>) serializer);
}
return serializer;
}
});
}
});
3.4. 样本输出
这是一个简单的序列化示例:
Address ad1 = new Address("tokyo", "jp", true);
Address ad2 = new Address("london", "uk", false);
Address ad3 = new Address("ny", "usa", false);
Person p1 = new Person("john", ad1, false);
Person p2 = new Person("tom", ad2, true);
Person p3 = new Person("adam", ad3, false);
System.out.println(mapper.writeValueAsString(Arrays.asList(p1, p2, p3)));
输出是:
[
{
"name":"john"
},
{
"name":"adam",
"address":{
"city":"ny",
"country":"usa"
}
}
]
3.5. 测试
最后——这里有几个测试用例: 第一种情况,什么都没有隐藏:
@Test
public void whenNotHidden_thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", false);
Person person = new Person("john", ad, false);
String result = mapper.writeValueAsString(person);
assertTrue(result.contains("name"));
assertTrue(result.contains("john"));
assertTrue(result.contains("address"));
assertTrue(result.contains("usa"));
}
接下来,只隐藏地址:
@Test
public void whenAddressHidden_thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", true);
Person person = new Person("john", ad, false);
String result = mapper.writeValueAsString(person);
assertTrue(result.contains("name"));
assertTrue(result.contains("john"));
assertFalse(result.contains("address"));
assertFalse(result.contains("usa"));
}
现在,整个人都被隐藏了:
@Test
public void whenAllHidden_thenCorrect() throws JsonProcessingException {
Address ad = new Address("ny", "usa", false);
Person person = new Person("john", ad, true);
String result = mapper.writeValueAsString(person);
assertTrue(result.length() == 0);
}