如何删除杰克逊自定义序列化程序生成的空值?

Posted

技术标签:

【中文标题】如何删除杰克逊自定义序列化程序生成的空值?【英文标题】:How to remove null values generated by a jackson custom serializer? 【发布时间】:2020-06-12 10:29:41 【问题描述】:

给定以下类:

@JsonInclude(JsonInclude.Include.NON_EMPTY)
public class Account 

    [... A lot of serialized properties]

    @JsonSerialize(nullsUsing = JacksonSpringSpelSerializer.class, using = JacksonSpringSpelSerializer.class)
    @JsonView(View.Contract.class)
    @Value("#@contractService.getActiveContract(#this)")
    public Contract activeContract;


基本上activeContract 属性为null,只有在提供正确的@JsonView 时才会评估其值,该值由Spring Spel 表达式计算,一切都在自定义序列化器JacksonSpringSpelSerializer 中完成。

一切都按预期工作,但计算值有时可能为空,这是正常的,我最终得到一个像这样的 json:


    [... All properties],
    "activeContract": null

问题是我不希望返回的 json 中有 null 属性,当在属性上设置自定义序列化程序时,@JsonInclude(JsonInclude.Include.NON_EMPTY) 会被忽略。

经过一番挖掘,我发现自定义序列化程序是由BeanPropertyWriter.serializeAsField()调用的,其中包含:

    if (value == null) 
        if (_nullSerializer != null) 
            gen.writeFieldName(_name);
            _nullSerializer.serialize(null, gen, prov);
        
        return;
    

所以字段的名称是在实际调用自定义序列化程序之前由gen.writeFieldName(_name);编写的,我没有找到适当的方法来防止这种行为或删除自定义序列化程序生成的空属性。

有没有合适的方法来达到这样的结果?任何建议都会非常受欢迎:D

谢谢

【问题讨论】:

如果是客户 Jackson 序列化程序,您不能在自定义序列化程序的 serialize() 方法中添加跳过空字段的逻辑吗? 这就是我所做的,但是序列化程序是由一个首先写入属性名称的类调用的。如果我的序列化程序什么都不做,我会得到 "activeContract" 。如果序列化程序执行gen.writeNull();我得到 "activeContract": null 。我没有找到从序列化程序本身跳过该字段的方法 当您想将JsonInclude.Include.NON_EMPTY与自定义序列化器一起使用时,您还需要实现isEmpty方法。看看类似的例子:How can I serialize double value null and not return when 0.0 我试过但不幸的是它没有工作,对于同样的问题,该字段的值为 null 并且可能由序列化程序填充。如果注释字段已经为空,Jackson BeanPropertyWriter 不会检查 isEmpty 方法:github.com/FasterXML/jackson-databind/blob/… 它适用于双重情况​​,因为序列化属性不为空,但可能 【参考方案1】:

你可以尝试使用JsonInclude.Include.NON_NULL,如下代码

@JsonInclude(JsonInclude.Include.NON_NULL)

【讨论】:

这就是我尝试过的,但如果字段具有自定义序列化器并且 JsonInclude 被忽略,则它似乎不起作用 @JsonSerialize(使用 = JacksonSpringSpelSerializer.class) ;删除 'nullsUsing = JacksonSpringSpelSerializer.class',它可能会正常工作 我不能,因为该值为null,并且由序列化程序填充^^【参考方案2】:

如果您已经在全局或现场以某种方式指定了Include.NON_EMPTY,您还必须覆盖com.fasterxml.jackson.databind.JsonSerializer#isEmpty(com.fasterxml.jackson.databind.SerializerProvider, T)

static class Serializer extends JsonSerializer<Foo> 

    @Override
    public void serialize(Foo value, JsonGenerator gen, SerializerProvider serializers) throws IOException 
        // serialize
    

    @Override
    public boolean isEmpty(SerializerProvider provider, Foo value) 
        // this will be called for Include.NON_EMPTY
        boolean isItEmpty = // get it somehow
        return isItEmpty;
    

【讨论】:

【参考方案3】:

这可以通过在注解中添加 include 属性来解决:

 @JsonSerialize(using=JacksonSpringSpelSerializer.class, include=JsonInclude.NON_NULL)

JsonSerialize 中此字段级别的默认值为 ALWAYS,它会覆盖类级别设置,因此会出现不希望的行为。

【讨论】:

以上是关于如何删除杰克逊自定义序列化程序生成的空值?的主要内容,如果未能解决你的问题,请参考以下文章

如何从杰克逊 XML 解析中删除命名空间定义

如何从列类型列表中删除 pandas DataFrame 中的空值

如何使用无点递归实现使用 Ramda 删除对象中的空值?

如何序列化数组中的空值?

如何从 Vuetify 进度条计算中删除空值

js中怎么去掉数组的空值,不知道是第几个,只要是空值就删除