1. 概述

本教程将展示如何使用Jackson 2.x将对象序列化为JSON时忽略特定字段

当Jackson的默认设置不够用,我们需要精确控制序列化到JSON的内容时,这非常有用。有多种方法可以忽略属性。

要深入了解并学习我们还可以使用Jackson做的其他酷炫事情,请访问Jackson主教程

2. 类级别忽略字段

我们可以在类级别上忽略特定字段,使用**@JsonIgnoreProperties注解**并按名称指定字段:

@JsonIgnoreProperties(value = { "intValue" })
public class MyDto {

    private String stringValue;
    private int intValue;
    private boolean booleanValue;

    public MyDto() {
        super();
    }

    // standard setters and getters are not shown
}

现在我们可以测试,写入JSON后,该字段确实不在输出中:

@Test
public void givenFieldIsIgnoredByName_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();
    MyDto dtoObject = new MyDto();

    String dtoAsString = mapper.writeValueAsString(dtoObject);

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

3. 字段级别忽略字段

我们也可以直接在字段上通过**@JsonIgnore注解**来忽略字段:

public class MyDto {

    private String stringValue;
    @JsonIgnore
    private int intValue;
    private boolean booleanValue;

    public MyDto() {
        super();
    }

    // standard setters and getters are not shown
}

现在我们可以测试,intValue字段确实不在序列化后的JSON输出中:

@Test
public void givenFieldIsIgnoredDirectly_whenDtoIsSerialized_thenCorrect() 
  throws JsonParseException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();
    MyDto dtoObject = new MyDto();

    String dtoAsString = mapper.writeValueAsString(dtoObject);

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

4. 按类型忽略所有字段

最后,我们可以使用**@JsonIgnoreType注解**按类型忽略所有指定类型的字段。如果我们控制了类型,那么可以直接在类上注解:

@JsonIgnoreType
public class SomeType { ... }

然而,通常我们无法控制类本身。在这种情况下,我们可以充分利用Jackson混入

首先,我们为要忽略的类型定义一个混入,并在其上注解@JsonIgnoreType

@JsonIgnoreType
public class MyMixInForIgnoreType {}

然后我们在序列化期间注册这个混入,以忽略所有String[]类型:

mapper.addMixInAnnotations(String[].class, MyMixInForIgnoreType.class);

此时,所有String数组将被忽略,而不是序列化为JSON:

@Test
public final void givenFieldTypeIsIgnored_whenDtoIsSerialized_thenCorrect()
  throws JsonParseException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();
    mapper.addMixIn(String[].class, MyMixInForIgnoreType.class);
    MyDtoWithSpecialField dtoObject = new MyDtoWithSpecialField();
    dtoObject.setBooleanValue(true);

    String dtoAsString = mapper.writeValueAsString(dtoObject);

    assertThat(dtoAsString, containsString("intValue"));
    assertThat(dtoAsString, containsString("booleanValue"));
    assertThat(dtoAsString, not(containsString("stringValue")));
}

这是我们的DTO:

public class MyDtoWithSpecialField {
    private String[] stringValue;
    private int intValue;
    private boolean booleanValue;
}

注意:自2.5版本以来,似乎无法使用此方法忽略基本数据类型,但我们可以用于自定义类型和数组。

5. 使用过滤器忽略字段

最后,我们还可以使用过滤器来忽略特定字段在Jackson中。

首先,我们需要在Java对象上定义过滤器:

@JsonFilter("myFilter")
public class MyDtoWithFilter { ... }

然后我们定义一个简单的过滤器,它将忽略intValue字段:

SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter
  .serializeAllExcept("intValue");
FilterProvider filters = new SimpleFilterProvider()
  .addFilter("myFilter", theFilter);

现在我们可以序列化对象,并确保intValue字段不在JSON输出中:

@Test
public final void givenTypeHasFilterThatIgnoresFieldByName_whenDtoIsSerialized_thenCorrect() 
  throws JsonParseException, IOException {
 
    ObjectMapper mapper = new ObjectMapper();
    SimpleBeanPropertyFilter theFilter = SimpleBeanPropertyFilter
      .serializeAllExcept("intValue");
    FilterProvider filters = new SimpleFilterProvider()
      .addFilter("myFilter", theFilter);

    MyDtoWithFilter dtoObject = new MyDtoWithFilter();
    String dtoAsString = mapper.writer(filters).writeValueAsString(dtoObject);

    assertThat(dtoAsString, not(containsString("intValue")));
    assertThat(dtoAsString, containsString("booleanValue"));
    assertThat(dtoAsString, containsString("stringValue"));
    System.out.println(dtoAsString);
}

6. 总结

本文展示了如何在序列化时忽略字段。我们首先按名称忽略,然后直接忽略,最后通过混入和过滤器来完全控制输出。

所有示例和代码片段的实现可以在GitHub项目中找到。