如何在Jackson序列化Kotlin API模型时排除NO_OP默认值字段?
当然可以做到!Jackson有几种适配你这种空对象模式的方案,我给你拆解一下最实用的几种:
方案1:自定义JSON包含过滤规则(最推荐)
Jackson的@JsonInclude注解支持自定义过滤条件,我们可以直接判断字段值是否为NO_OP单例,是的话就不把该字段包含到生成的JSON中。
步骤1:创建全局过滤规则
先定义一个过滤对象,用来识别ClassOne.NO_OP和ClassTwo.NO_OP:
object NoOpFilter : JsonInclude.IncludeFilter() { override fun equals(value: Any?): Boolean { // 用引用相等判断,确保只匹配单例NO_OP return value === ClassOne.NO_OP || value === ClassTwo.NO_OP } }
步骤2:给数据类添加注解
把这个过滤规则应用到你的MyParam类上,这样所有字段都会自动检查是否为NO_OP:
@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = NoOpFilter::class) data class MyParam( val name: String, val myField1: ClassOne = ClassOne.NO_OP, val myField2: ClassTwo = ClassTwo.NO_OP )
灵活调整:针对单个字段设置
如果你不想全局应用,只想给特定字段单独配置,可以直接在字段上添加注解:
data class MyParam( val name: String, @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = ClassOneNoOpFilter::class) val myField1: ClassOne = ClassOne.NO_OP, @JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = ClassTwoNoOpFilter::class) val myField2: ClassTwo = ClassTwo.NO_OP ) // 针对ClassOne的单独过滤规则 object ClassOneNoOpFilter : JsonInclude.IncludeFilter() { override fun equals(value: Any?): Boolean = value === ClassOne.NO_OP } // 针对ClassTwo的单独过滤规则 object ClassTwoNoOpFilter : JsonInclude.IncludeFilter() { override fun equals(value: Any?): Boolean = value === ClassTwo.NO_OP }
方案2:自定义序列化器(适合复杂场景)
如果你的ClassOne/ClassTwo有复杂的序列化逻辑,同时需要跳过NO_OP,可以给它们编写自定义序列化器,在序列化时直接跳过NO_OP实例:
class ClassOneSerializer : StdSerializer<ClassOne>(ClassOne::class.java) { override fun serialize(value: ClassOne, gen: JsonGenerator, provider: SerializerProvider) { if (value !== ClassOne.NO_OP) { // 在这里编写ClassOne的正常序列化逻辑 gen.writeStartObject() gen.writeStringField("fieldA", value.fieldA) gen.writeIntField("fieldB", value.fieldB) gen.writeEndObject() } // 如果是NO_OP,什么都不写,结合@JsonInclude(Include.NON_NULL)的话,字段会被忽略 } } // 同理编写ClassTwoSerializer
然后在你的类上注册序列化器:
@JsonSerialize(using = ClassOneSerializer::class) class ClassOne { // ...类定义 companion object { val NO_OP = ClassOne() } }
关键注意事项
- 一定要保证
ClassOne.NO_OP和ClassTwo.NO_OP是单例对象(比如用object声明或者在companion object里定义为固定实例),这样===的引用相等判断才会准确,避免误过滤正常的业务实例。 - 如果你的类重写了
equals方法,可以把过滤条件里的===改成==,但单例的引用相等判断性能更好,也更安全。
内容的提问来源于stack exchange,提问作者metacubed
相关产品推荐
相关产品推荐

