动态忽略 Jackson 中的字段
1、简介
本文将带你了解如何在 Jackson 中通过 @JsonFilter
、@JsonView
和 Jackson Mixin(混合) 实现动态忽略字段。
2、项目设置
添加 Jackson 库:
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.2</version>
</dependency>
最新版本可在 此处 找到。
3、使用 @JsonFilter
第一种方法是通过 @JsonFilter
注解指定在序列化过程中使用的过滤器。
使用 @JsonFilter
对类进行注解:
@JsonFilter("publicFilter") // 指定 Filter 名称
public class UserWithFilter {
private Long id;
private String name;
//Getter/Setter 忽略
}
然后,动态配置 ObjectMapper
,并注册 PropertyFilter
来序列化除 id
之外的所有字段:
SimpleFilterProvider filterProvider = new SimpleFilterProvider();
// 注册 Filter,指定名字
filterProvider.addFilter("publicFilter", SimpleBeanPropertyFilter.serializeAllExcept("id"));
ObjectMapper objectMapper = new ObjectMapper().setFilterProvider(filterProvider);
然后,使用 objectMapper
序列化 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;
// Getter / Setter 忽略
public interface PublicView {}
public interface InternalView extends PublicView {}
}
在运行时,我们可以通过配置 ObjectMapper
来选择序列化对象时要使用的 JsonView
:
ObjectWriter objectWriter = new ObjectMapper().writerWithView(UserWithView.PublicView.class);
在这种情况下,结果不包含 ID
字段,因为 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、使用 Mixin 动态应用 @JsonIgnore
Jackson Mixin(混合)提供了一种无需修改原始类即可应用 @JsonIgnore
注解的方法。
首先,需要定义一个接口,并在要忽略的属性上定义一个 getter 方法:
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
注解与 Mixin 配置一起使用,使得 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 | 中 | 在编译时定义多个序列化视图,以便在运行时动态切换 | ✅ |
Mixin(混合) | 中 | 在不修改原始类的情况下应用 @JsonIgnore | ✅ |
7、总结
本文介绍了在使用 Jackson 对对象进行序列化和反序列化时实现动态忽略字段的一些方法。
Ref:https://www.baeldung.com/java-jackson-fields-dynamic-ignore