1. 簡介
本教程將介紹如何動態忽略 Jackson 中的字段。
這在我們需要根據特定條件對相同對象進行序列化和反序列化時非常有用。
我們將探索三種實現這一目標的方法:<em >@JsonFilter, @JsonView</em> 以及 Jackson Mixins。
2. 項目設置
讓我們通過添加所需的 Jackson 庫開始我們的教程:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>最新版本可以在這裏找到:這裏。
3. 使用 <em @JsonFilter@ 動態忽略
我們將首先探討一種通過註解指定在序列化過程中使用的過濾器的做法。
通過對 類</em class="em">使用 <em @JsonFilter@ 註解,可以實現...
@JsonFilter("publicFilter")
public class UserWithFilter {
private Long id;
private String name;
// getters and setters
}我們可以動態配置 ObjectMapper,並註冊一個 PropertyFilter,以序列化所有字段,但不包括 id:
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
filterProvider.addFilter("publicFilter", SimpleBeanPropertyFilter.serializeAllExcept("id"));
ObjectMapper objectMapper = new ObjectMapper().setFilterProvider(filterProvider);
然後我們可以序列化 UserWithFilter 對象:
UserWithFilter user = new UserWithFilter(1000L, "John");
String result = objectMapper.writeValueAsString(user);
assertThat(result).contains("John");
assertThat(result).doesNotContain("1000")此方法提供了巨大的靈活性,因為我們可以選擇在運行時序列化哪些字段。
不幸的是,此方法不支持動態反序列化對象: 即使我們使用相同的過濾器提供程序自定義 ObjectMapper,id 字段仍會在對象中被反序列化。
String json = "{\"id\":1000,\"name\":\"John\"}";
UserWithFilter result = objectMapper.readValue(json, UserWithFilter.class);
assertEquals(1000L, result.getId());
assertEquals("John", result.getName());在下一部分,我們將看到另一種方法,它在反序列化對象時也能正常工作。
4. 使用 @JsonView 進行條件忽略
@JsonView 是一種通過定義不同視圖來控制字段可見性的方法。與之前的做法不同,我們需要在編譯時定義序列化選項:
public class UserWithView {
@JsonView(InternalView.class)
private Long id;
@JsonView(PublicView.class)
private String name;
// getters and setters
public interface PublicView {}
public interface InternalView extends PublicView {}
}
在運行時,我們可以通過配置 ObjectMapper,選擇合適的 JsonView 用於對象序列化。
ObjectWriter objectWriter = new ObjectMapper().writerWithView(UserWithView.PublicView.class);在這種情況下,結果將不包含 ID 字段,該字段僅存在於 InternalView 中:
String result = objectWriter.writeValueAsString(user);
assertThat(result).contains("John");
assertThat(result).doesNotContain("1000")使用 @JsonView 動態方法,也適用於將 JSON 解析為對象。
String json = "{\"id\":1000,\"name\":\"John\"}";
ObjectReader objectReader = new ObjectMapper().readerWithView(UserWithView.PublicView.class)
.forType(UserWithView.class);
UserWithView user = objectReader.readValue(json);
assertEquals("John", user.getName());
assertNull(user.getId());在反序列化時,我們需要使用 readerWithView() 方法而不是 writerWithView() 方法來定製 ObjectMapper.
5. 使用 混合模式 動態應用 @JsonIgnore 註解
Jackson 混合模式提供了一種在不修改原始類的情況下 應用 @JsonIgnore 註解 的方法。我們需要定義一個接口,該接口包含一個獲取器方法,用於指定要忽略的屬性:
public interface PublicMixin {
@JsonIgnore
Long getId();
}然後,我們可以將接口註冊為 ObjectMapper 中的 Mixin,從而實現所需的功能:
ObjectMapper objectMapper = new ObjectMapper().addMixIn(UserWithMixin.class, PublicMixin.class);
String result = objectMapper.writeValueAsString(user);
assertThat(result).contains("John");
assertThat(result).doesNotContain("1000");
@JsonIgnore 註解通過混合配置動態注入,使得 Jackson 在反序列化對象時也忽略字段:
String json = "{\"id\":1000,\"name\":\"John\"}";
ObjectMapper objectMapper = new ObjectMapper().addMixIn(UserWithMixin.class, UserWithMixin.PublicMixin.class);
UserWithMixin user = objectMapper.readValue(json, UserWithMixin.class);
assertNull(user.getId());
assertEquals("John", user.getName());
在這種情況下,序列化和反序列化不需要進行特定定製。 只需要設置正確的 Mixin 類即可。
在下一部分,我們將總結我們評估的這三種方法。
6. 比較方法
以下是幾種方法的比較,從靈活性、序列化/反序列化以及最佳使用案例等方面進行分析:
| 方法 | 運行時靈活性 | 使用案例 | 序列化/反序列化 |
|---|---|---|---|
| @JsonFilter | 高 | 在運行時動態排除字段 | 否 |
| @JsonView | 中 | 在編譯時定義多個序列化視圖,並在運行時動態切換 | 是 |
| Mixins | 中 | 在不修改原始類的情況下應用@JsonIgnore | 是 |
此表總結了每種方法的優勢和權衡。選擇哪種方法通常取決於我們是否需要序列化和反序列化工作,是否需要高運行時靈活性,或者是否不希望修改現有源代碼。
7. 結論
在本文中,我們探討了使用 Jackson 動態序列化和反序列化對象的幾種方法。對於像 Java 這樣編譯型語言,實現完全的運行時動態性非常困難。然而,Jackson 提供了多種機制,可以自定義序列化行為,並根據不同的運行時需求調整輸出。