Jackson 序列化期间如何跳过 Optional.empty 字段?
Posted
技术标签:
【中文标题】Jackson 序列化期间如何跳过 Optional.empty 字段?【英文标题】:How to skip Optional.empty fields during Jackson serialization? 【发布时间】:2017-03-17 10:15:23 【问题描述】:我有一个带有 Optional 字段的 Java 类。我正在使用 Jackson 2.8.3(从 Spring web 4.3.3 调用)将类序列化为 JSON。
如果 Optional 为空,我希望让序列化程序跳过该字段,并序列化包含的字符串(如果存在)。我正在寻找包含两个对象的列表的结果示例:
[
"id": 1,
"foo": "bar"
,
"id": 2,
]
对于 id 为 2 的对象,这里的 foo Optional 为空。
相反,我得到的是:
[
"id": 1,
"foo":
"present": true
,
"id": 2,
"foo":
"present": false
]
即使我在类中注释“栏”字段,这也是结果
@JsonInclude(JsonInclude.Include.NON_ABSENT)
public Optional<String> getFoo() ...
有没有什么方法可以使用 Jackson 注释或自定义序列化程序来实现第一个列表之类的结果?
【问题讨论】:
顺便说一句,使用Optional
作为 bean 的字段通常是一个 Bad Idea™。
为什么这被认为是有问题的?
它不是为这种用途而设计的。这是一个非常微妙的语义差异,但在字段的情况下,null
被认为只是另一个值。如果您在库的 API 中设计方法,您可能需要强调它可能不会返回值,因此使用Optional
。查看更多here
【参考方案1】:
根据您的需要使用JsonSerializer
。
类似这样的东西(半伪):
public class MySer extends JsonSerializer<Opional<?>>
@Override
public void serialize(Optional<?> optString, JsonGenerator generator, SerializerProvider provider)
throws IOException, JsonProcessingException
//Check Optional here...
generator.writeString(/* DO SOMETHING HERE WHATEVER */);
//然后在你的模型中:
public class ClassWhatever
@JsonSerialize(using = MySer .class)
public Optional<String> getFoo() ...
为避免使用 @JsonSerialize 注释每个字段,您可以使用
将自定义序列化程序注册到对象映射器 ObjectMapper mapper = new ObjectMapper();
SimpleModule testModule = new SimpleModule("MyModule", new Version(1, 0, 0, null));
testModule.addSerializer(new MyCustomSerializer()); // assuming serializer declares correct class to bind to
mapper.registerModule(testModule);
此外,给定的解决方案仅适用于序列化。除非您编写自己的反序列化器,否则反序列化将失败。然后您需要使用@JsonDeserializ
e 注释每个字段或注册您的自定义反序列化器。
【讨论】:
com.fasterxml.jackson.datatype:jackson-datatype-jdk8 是更好的选择。使用这样的自定义解决方案,您需要注释每个字段。此外,除非您编写自定义反序列化程序并使用 @JsonDeserialize 注释每个字段,否则反序列化将不起作用 @BartoszBilicki 当然,同意你的意见。两者都可以,但您的建议更好。【参考方案2】:无需编写自定义序列化程序。使用 @JsonInclude(JsonInclude.Include.NON_ABSENT)
注释您的课程。
您还需要:
包括com.fasterxml.jackson.datatype:jackson-datatype-jdk8
作为您的依赖项
并向您的对象映射器注册相应的模块:objectMapper.registerModule(new Jdk8Module());
【讨论】:
谢谢,包括对 com.fasterxml.jackson.datatype:jackson-datatype-jdk8 的依赖。 @JsonInclude(JsonInclude.Include.NON_ABSENT) 就足够了。 要排除 Optional.empty() 字段,正如 OP 最初要求的那样,必须添加依赖项并必须设置 NON_ABSENT。 NON_NULL 是不够的。【参考方案3】:您可以使用objectMapper.registerModule(new Jdk8Module());
,但它会使用空值进行序列化。
但您仍然想从 JSON 中删除空值,请使用以下代码:
objectMapper.registerModule(new Jdk8Module().configureAbsentsAsNulls(true));
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
【讨论】:
以上是关于Jackson 序列化期间如何跳过 Optional.empty 字段?的主要内容,如果未能解决你的问题,请参考以下文章
在使用 Jackson 反序列化期间选择性地忽略 JSON 属性
在 Java 中的 Jackson JSON 反序列化期间忽略丢失的属性
使用 com.fasterxml.jackson.databind.ObjectMapper 在序列化/反序列化 JSON 内容期间从异常日志中删除敏感数据