Jackson – Decide What Fields Get Serialized/Deserialized – Jackson – 决定哪些字段被序列化/反序列化

最后修改: 2015年 5月 31日

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

1. Overview

1.概述

In this article we’ll explore the various ways we can control if a field is serialized / deserialized by Jackson or not.

在这篇文章中,我们将探索各种方法,以控制一个字段是否被Jackson序列化/反序列化

2. A Public Field

2.一个公共领域

The simplest way to make sure a field is both serializable and deserializable is to make it public.

确保一个字段既可序列化又可反序列化的最简单方法是使其公开。

Let’s declare a simple class with a public, a package-private and a private

让我们声明一个简单的类,它有一个public,一个package-private和一个private

public class MyDtoAccessLevel {
    private String stringValue;
    int intValue;
    protected float floatValue;
    public boolean booleanValue;
    // NO setters or getters
}

Out of the four fields of the class, just the public booleanValue will be serialized to JSON by default:

在该类的四个字段中,只有公共的booleanValue将被默认序列化为JSON。

@Test
public void givenDifferentAccessLevels_whenPublic_thenSerializable() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    MyDtoAccessLevel dtoObject = new MyDtoAccessLevel();

    String dtoAsString = mapper.writeValueAsString(dtoObject);
    assertThat(dtoAsString, not(containsString("stringValue")));
    assertThat(dtoAsString, not(containsString("intValue")));
    assertThat(dtoAsString, not(containsString("floatValue")));

    assertThat(dtoAsString, containsString("booleanValue"));
}

3. A Getter Makes a Non-Public Field Serializable and Deserializable

3.一个Getter使一个非公共字段可序列化和反序列化

Now, another simple way to make a field – especially a non-public field – serializable, is to add a getter for it:

现在,使一个字段–特别是一个非公共字段–可序列化的另一个简单方法是为它添加一个getter。

public class MyDtoWithGetter {
    private String stringValue;
    private int intValue;

    public String getStringValue() {
        return stringValue;
    }
}

We now expect the stringValue field to be serializable, while the other private field not to be, as it has no getter:

我们现在希望stringValue字段是可序列化的,而其他私有字段则不是,因为它没有getter。

@Test
public void givenDifferentAccessLevels_whenGetterAdded_thenSerializable() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    MyDtoGetter dtoObject = new MyDtoGetter();

    String dtoAsString = mapper.writeValueAsString(dtoObject);
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, not(containsString("intValue")));
}

Unintuitively, the getter also makes the private field deserializable as well – because once it has a getter, the field is considered a property.

不合常理的是,这个getter也使得私有字段可以反序列化–因为一旦它有了getter,这个字段就被视为一个属性。

Let’s look at how that work:

让我们来看看如何工作。

@Test
public void givenDifferentAccessLevels_whenGetterAdded_thenDeserializable() 
  throws JsonProcessingException, JsonMappingException, IOException {
    String jsonAsString = "{\"stringValue\":\"dtoString\"}";
    ObjectMapper mapper = new ObjectMapper();
    MyDtoWithGetter dtoObject = mapper.readValue(jsonAsString, MyDtoWithGetter.class);

    assertThat(dtoObject.getStringValue(), equalTo("dtoString"));
}

4. A Setter Makes a Non-Public Field Deserializable Only

4.一个设置者使一个非公共域只能被反序列化

We saw how the getter made the private field both serializable and deserializable. On the other hand, a setter will only mark the non-public field as deserializable:

我们看到getter如何使私有字段既可序列化又可反序列化。另一方面,setter将只把非公共字段标记为可反序列化。

public class MyDtoWithSetter {
    private int intValue;

    public void setIntValue(int intValue) {
        this.intValue = intValue;
    }

    public int accessIntValue() {
        return intValue;
    }
}

As you can see, the private intValue field only has a setter this time. We do have a way to access the value, but that’s not a standard getter.

正如你所看到的,私有intValue字段这次只有一个setter。我们确实有一种方法来访问这个值,但那不是一个标准的getter。

The unmarshalling process for intValue should work correctly:

intValue的解封过程应该可以正常工作。

@Test
public void givenDifferentAccessLevels_whenSetterAdded_thenDeserializable() 
  throws JsonProcessingException, JsonMappingException, IOException {
    String jsonAsString = "{\"intValue\":1}";
    ObjectMapper mapper = new ObjectMapper();

    MyDtoSetter dtoObject = mapper.readValue(jsonAsString, MyDtoSetter.class);

    assertThat(dtoObject.anotherGetIntValue(), equalTo(1));
}

And as we mentioned, the setter should only make the field deserializable, but not serializable:

正如我们所提到的,setter应该只使字段可反序列化,而不是可序列化。

@Test
public void givenDifferentAccessLevels_whenSetterAdded_thenStillNotSerializable() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    MyDtoSetter dtoObject = new MyDtoSetter();

    String dtoAsString = mapper.writeValueAsString(dtoObject);
    assertThat(dtoAsString, not(containsString("intValue")));
}

5. Make All Fields Globally Serializable

5.让所有的字段都能在全球范围内序列化

In some cases where, for example, you might not actually be able to modify the source code directly – we need to configure the way Jackson deals with non-public fields from the outside.

在某些情况下,例如,你可能实际上不能直接修改源代码–我们需要配置Jackson从外部处理非公开字段的方式。

That kind of global configuration can be done at the ObjectMapper level, by turning on the AutoDetect function to use either public fields or getter/setter methods for serialization, or maybe turn on serialization for all fields:

这种全局配置可以在ObjectMapper级别完成,通过打开AutoDetect函数来使用public字段或getter/setter方法进行序列化,或者也许打开所有字段的序列化。

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, Visibility.NONE);
mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

The following test case verifies all member fields (including non-public) of MyDtoAccessLevel are serializable:

下面的测试案例验证了MyDtoAccessLevel的所有成员字段(包括非公共字段)是可序列化的。

@Test
public void givenDifferentAccessLevels_whenSetVisibility_thenSerializable() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();
    mapper.setVisibility(PropertyAccessor.FIELD, Visibility.ANY);

    MyDtoAccessLevel dtoObject = new MyDtoAccessLevel();

    String dtoAsString = mapper.writeValueAsString(dtoObject);
    assertThat(dtoAsString, containsString("stringValue"));
    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
}

6. Change the Name of a Property on Serialization/Deserialization

6.在序列化/反序列化时改变属性的名称

Going beyond controlling which field gets serialized or deserialized, you can also have control over the way a fields maps to JSON and back. I covered this configuration here.

除了控制哪个字段被序列化或反序列化之外,您还可以控制一个字段映射到JSON和返回的方式。我在这里介绍了这种配置

7. Ignore a Field on Serialization or Deserialization

7.在序列化或反序列化时忽略一个字段

Following this tutorial, we have a guide for how to ignore a field completely on serialization and deserialization.

按照本教程,我们有一个指南,说明如何在序列化和反序列化时完全忽略一个字段。

However, sometimes we only need to ignore the field on either, but not on both. Jackson is flexible enough to accommodate this interesting usecase as well.

然而,有时我们只需要忽略其中一个字段,而不是两个字段。杰克逊也有足够的灵活性来适应这种有趣的用例。

The following example shows a User object which contains sensitive password information which shouldn’t be serialized to JSON.

下面的例子显示了一个User对象,它包含敏感的密码信息,不应该被序列化为JSON。

To get there, we simply add the @JsonIgnore annotation on the getter of the password, and enable deserialization for the field by applying the @JsonProperty annotation on the setter:

为了达到这个目的,我们只需在password的getter上添加@JsonIgnore注解,并通过在setter上应用@JsonProperty注解为该字段启用反序列化。

@JsonIgnore
public String getPassword() {
    return password;
}
@JsonProperty
public void setPassword(String password) {
    this.password = password;
}

Now the password information won’t be serialized to JSON:

现在,密码信息不会被序列化为JSON。

@Test
public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsSerialized_thenIgnored() 
  throws JsonProcessingException {
    ObjectMapper mapper = new ObjectMapper();

    User userObject = new User();
    userObject.setPassword("thePassword");

    String userAsString = mapper.writeValueAsString(userObject);
    assertThat(userAsString, not(containsString("password")));
    assertThat(userAsString, not(containsString("thePassword")));
}

However, the JSON containing the password will be successfully deserialized to the User object:

然而,包含密码的JSON将被成功反序列化为User对象。

@Test
public void givenFieldTypeIsIgnoredOnlyAtSerialization_whenUserIsDeserialized_thenCorrect() 
  throws JsonParseException, JsonMappingException, IOException {
    String jsonAsString = "{\"password\":\"thePassword\"}";
    ObjectMapper mapper = new ObjectMapper();

    User userObject = mapper.readValue(jsonAsString, User.class);

    assertThat(userObject.getPassword(), equalTo("thePassword"));
}

8. Conclusion

8.结论

This tutorial goes over the basic of how Jackson chooses which field is serialized/deserialized and which gets ignored in the process and of course how to get fully control over it.

本教程将介绍Jackson如何选择哪个字段被序列化/反序列化,哪个字段被忽略的基本情况,当然还有如何完全控制它。

You may also get to the next step in understanding Jackson 2 by diving deeper with articles such as ignoring a field, deserializing a JSON Array to a Java Array or Collection.

你也可以通过深入了解诸如ignoring a fielddeserializing a JSON Array to a Java Array or Collection等文章来深入了解Jackson 2。

The implementation of all these examples and code snippets can be found in my github project – this is an Eclipse based project, so it should be easy to import and run as it is.

所有这些例子和代码片段的实现都可以在我的github项目中找到 – 这是一个基于Eclipse的项目,所以它应该很容易导入并按原样运行。