知識庫 / JSON / Jackson RSS 訂閱

使用 Jackson 僅序列化滿足自定義條件的字段

Data,Jackson
HongKong
6
10:04 PM · Dec 05 ,2025

1. 概述

本教程將演示如何使用 Jackson 僅在滿足特定自定義條件時才序列化字段。

例如,假設我們只想在整數值為正數時才序列化它,如果不是則完全跳過。

如果您想深入瞭解更多關於使用 Jackson 2 的酷炫功能 – 請訪問主 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 字段確實不在 marshalled JSON 輸出中

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

3. 條件跳過對象

現在,我們來討論如何根據屬性 value 條件地跳過對象。我們將跳過所有屬性 hiddentrue 的對象:

3.1. 可隱藏類

首先,讓我們來查看一下我們的 可隱藏 接口:

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

我們有兩個簡單的類實現了這個接口 Person, Address

Person 類:

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

以及 類:

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

4. 結論

這種高級過濾功能非常強大,並且允許使用 Jackson 靈活自定義 JSON 序列化複雜對象時輸出的 json。

一種更靈活但同時也更復雜的替代方案是使用自定義序列化器來控制 JSON 輸出——如果這個解決方案不夠靈活,那麼可以考慮採用該方案。

user avatar
0 位用戶收藏了這個故事!
收藏

發佈 評論

Some HTML is okay.