避免使用 Jackson 自定义 JsonSerializer 和 JsonGenerator 序列化空字段
Avoid Serializing null fields with Jackson custom JsonSerializer and JsonGenerator
Jackson 序列化到 JSON 有一些很好的特性,例如 SerializationFeature.WRITE_NULL_MAP_VALUES,它允许您避免将空值写入序列化对象。
但是,如果我使用自定义 JsonSerializer,则此设置将被忽略,我不得不在对 writeStringField 的所有调用中进行空值检查。例如,我注册了一个自定义的 JsonSerializer:
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(CloudDocument.class, new ImportProductSerializer());
objectMapper.registerModule(simpleModule);
然后在 ImportProductSerializer 内部,我一直坚持对我想要序列化的每个字段进行空检查,这变得丑陋乏味:
private class ImportProductSerializer extends JsonSerializer<CloudDocument> {
@Override
public void serialize(CloudDocument value,
JsonGenerator gen, //Customize this?
SerializerProvider serializers) throws Exception {
gen.writeStartObject();
gen.writeStringField("type", "add");
//Null check here and every other field: gross!
if(StringUtils.hasText(importProduct.getExtraListingSku1())) {
gen.writeStringField("extralistingsku1", importProduct.getExtraListingSku1());
}
gen.writeEndObject();
}
}
我想采用的解决方案是让我的自定义 JsonSerializer 使用自定义 JsonGenerator。 serialize 方法将 JsonGenerator 作为参数,我可以像这样轻松定义它:
private class CustomGenerator extends JsonGenerator {
@Override
public JsonGenerator setCodec(ObjectCodec oc) {
super.setCodec(oc);
}
@Override
public void writeStringField(String fieldName, String value) throws IOException {
if(value==null) return;
super.writeStringField(fieldName.toLowerCase(), value);
}
.... //other methods implemented
}
但我不确定如何配置 ObjectMapper 以使用我的 CustomGenerator 实现。这种方法的好处是我可以自定义 writeField 方法来执行 null 检查并确保字段名称订阅预期的命名约定,在这种情况下,涉及将 camelCase 转换为 lower_underscore.
有没有办法配置通过调用 objectMapper.writeValue() 实例化的 JsonGenerator?
这个问题有点开放性,因为我不知道你到目前为止到底做了什么;自定义序列化程序完成了多少工作。
一般而言,序列化程序应委托大部分处理以最大限度地减少它们所做的工作量。
但是,如果您已经定义了一个自定义序列化程序来处理包含字段的 POJO(而不是针对序列化为 JSON 字符串或其他标量值的内容的自定义序列化程序),是的,您确实需要处理你自己的支票。这部分是因为有很多方法可以潜在地改变包容性;不仅 SerializationFeature
,还有 @JsonFormat
属性注释;将控制委托给自定义序列化程序时,无法透明地处理此问题。
所以,是的,如果您最终使用 writeStringField()
,您确实需要检查默认包含设置并适当省略写入。
Jackson 序列化到 JSON 有一些很好的特性,例如 SerializationFeature.WRITE_NULL_MAP_VALUES,它允许您避免将空值写入序列化对象。
但是,如果我使用自定义 JsonSerializer,则此设置将被忽略,我不得不在对 writeStringField 的所有调用中进行空值检查。例如,我注册了一个自定义的 JsonSerializer:
ObjectMapper objectMapper = new ObjectMapper();
SimpleModule simpleModule = new SimpleModule();
simpleModule.addSerializer(CloudDocument.class, new ImportProductSerializer());
objectMapper.registerModule(simpleModule);
然后在 ImportProductSerializer 内部,我一直坚持对我想要序列化的每个字段进行空检查,这变得丑陋乏味:
private class ImportProductSerializer extends JsonSerializer<CloudDocument> {
@Override
public void serialize(CloudDocument value,
JsonGenerator gen, //Customize this?
SerializerProvider serializers) throws Exception {
gen.writeStartObject();
gen.writeStringField("type", "add");
//Null check here and every other field: gross!
if(StringUtils.hasText(importProduct.getExtraListingSku1())) {
gen.writeStringField("extralistingsku1", importProduct.getExtraListingSku1());
}
gen.writeEndObject();
}
}
我想采用的解决方案是让我的自定义 JsonSerializer 使用自定义 JsonGenerator。 serialize 方法将 JsonGenerator 作为参数,我可以像这样轻松定义它:
private class CustomGenerator extends JsonGenerator {
@Override
public JsonGenerator setCodec(ObjectCodec oc) {
super.setCodec(oc);
}
@Override
public void writeStringField(String fieldName, String value) throws IOException {
if(value==null) return;
super.writeStringField(fieldName.toLowerCase(), value);
}
.... //other methods implemented
}
但我不确定如何配置 ObjectMapper 以使用我的 CustomGenerator 实现。这种方法的好处是我可以自定义 writeField 方法来执行 null 检查并确保字段名称订阅预期的命名约定,在这种情况下,涉及将 camelCase 转换为 lower_underscore.
有没有办法配置通过调用 objectMapper.writeValue() 实例化的 JsonGenerator?
这个问题有点开放性,因为我不知道你到目前为止到底做了什么;自定义序列化程序完成了多少工作。 一般而言,序列化程序应委托大部分处理以最大限度地减少它们所做的工作量。
但是,如果您已经定义了一个自定义序列化程序来处理包含字段的 POJO(而不是针对序列化为 JSON 字符串或其他标量值的内容的自定义序列化程序),是的,您确实需要处理你自己的支票。这部分是因为有很多方法可以潜在地改变包容性;不仅 SerializationFeature
,还有 @JsonFormat
属性注释;将控制委托给自定义序列化程序时,无法透明地处理此问题。
所以,是的,如果您最终使用 writeStringField()
,您确实需要检查默认包含设置并适当省略写入。