Serialize Only Fields that meet a Custom Criteria with Jackson – 用Jackson只序列化符合自定义标准的字段

最后修改: 2013年 12月 22日

中文/混合/英文(键盘快捷键:t)

1. Overview

1.概述

This tutorial is going to illustrate how we can use Jackson to only serialize a field if it meets a specific, custom criteria.

本教程将说明我们如何使用Jackson只在一个字段满足特定的、自定义的标准时进行序列化

For example, say we only want to serialize an integer value if it’s positive – and we want to skip it entirely if it’s not.

例如,假设我们只想在一个整数值是正数的情况下进行序列化–如果不是,我们想完全跳过它。

If you want to dig deeper and learn other cool things you can do with the Jackson 2 – head on over to the main Jackson tutorial.

如果您想深入了解并学习您可以使用Jackson 2做的其他很酷的事情–请前往Jackson主要教程

2. Use Jackson Filter to Control the Serialization Process

2.使用Jackson过滤器来控制序列化过程

First, we need to define the filter on our entity, using the @JsonFilter annotation:

首先,我们需要使用@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;
    }
}

Then, we need to define our custom PropertyFilter:

然后,我们需要定义我们的自定义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;
   }
};

This filter contains the actual logic deciding if the intValue field is going to be serialized or not, based on its value.

这个过滤器包含实际的逻辑,根据intValue字段的值,决定是否要对其进行序列化

Next, we hook this filter into the ObjectMapper and we serialize an entity:

接下来,我们把这个过滤器挂到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);

And finally, we can check that the intValue field is indeed not part of the marshalled JSON output:

最后,我们可以检查intValue字段是否确实是不属于Marshalled JSON输出的一部分

assertThat(dtoAsString, not(containsString("intValue")));

3. Skip Objects Conditionally

3.有条件地跳过对象

Now – let’s discuss how to skip objects while serializing based on property value. We will skip all objects where property hidden is true:

现在–让我们讨论如何在序列化时根据属性value跳过对象。我们将跳过所有属性hiddentrue的对象。

3.1. Hidable Classes

3.1.可隐藏的类

First, let’s take a look at our Hidable Interface:

首先,让我们看一下我们的Hidable界面。

@JsonIgnoreProperties("hidden")
public interface Hidable {
    boolean isHidden();
}

And we have two simple classes implementing this interface Person, Address:

我们有两个简单的类实现这个接口PersonAddress

Person Class:

类。

public class Person implements Hidable {
    private String name;
    private Address address;
    private boolean hidden;
}

And Address Class:

地址类。

public class Address implements Hidable {
    private String city;
    private String country;
    private boolean hidden;
}

Note: We used @JsonIgnoreProperties(“hidden”) to make sure hidden property itself is not included in JSON

注意:我们使用@JsonIgnoreProperties(“hidden”)来确保hidden属性本身不包括在JSON中。

3.2. Custom Serializer

3.2.自定义串行器

Next – here is our custom serializer:

下一步–这里是我们的自定义序列化器。

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());
    }
}

Note that:

请注意,。

  • When the object will not be skipped, we delegate the serialization to the default injected serializer.
  • We overridden the method isEmpty() – to make sure that in case of Hidable object is a property, property name is also excluded from JSON.

3.3. Using BeanSerializerModifier

3.3.使用BeanSerializerModifier

Finally, we will need to use BeanSerializerModifier to inject default serializer in our custom HidableSerializer – as follows:

最后,我们需要使用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. Sample Output

3.4.输出样本

Here is a simple serialization example:

下面是一个简单的序列化例子。

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)));

And the output is:

而输出是。

[
    {
        "name":"john"
    },
    {
        "name":"adam",
        "address":{
            "city":"ny",
            "country":"usa"
        }
    }
]

3.5. Test

3.5.测试

Finally – here is few test cases:

最后–这里有几个测试案例。

First case, nothing is hidden:

第一种情况,没有什么是隐藏的

@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"));
}

Next, only address is hidden:

接下来,只有地址是隐藏的

@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"));
}

Now, entire person is hidden:

现在,整个人都被隐藏起来了

@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);
}

4. Conclusion

4.结论

This type of advanced filtering is incredibly powerful and allows very flexible customization of the json when serializing complex objects with Jackson.

这种类型的高级过滤功能非常强大,在用Jackson对复杂对象进行序列化时,可以非常灵活地定制json。

A more flexible but also more complex alternative would be using a fully custom serializer to control the JSON output – so if this solution isn’t flexible enough, it may be worth looking into that.

一个更灵活但也更复杂的选择是使用一个完全自定义的序列化器来控制JSON输出–所以如果这个解决方案不够灵活,可能值得研究一下。

The implementation of all these examples and code snippets can be found over on GitHub – it’s a Maven-based project, so it should be easy to import and run as it is.

所有这些例子和代码片段的实现可以在GitHub上找到over on GitHub – 这是一个基于Maven的项目,所以应该很容易导入和运行。