Jackson反序列化失败时为可空字段默认赋值null的通用实现方案
通用Jackson反序列化容错方案
以下提供两种适配不同场景的实现方案:
方案1:注解粒度控制(灵活推荐)
适合仅需要给指定字段开启容错的场景,不会影响全局反序列化逻辑,可适配任意类型的可空子对象。
1. 实现通用容错反序列化器
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.JavaType import com.fasterxml.jackson.databind.deser.std.StdDeserializer class NullOnErrorDeserializer<T>(private val targetType: JavaType) : StdDeserializer<T>(targetType) { override fun deserialize(jp: JsonParser, ctxt: DeserializationContext): T? { return runCatching { ctxt.readValue<T>(jp, targetType) }.getOrNull().also { // 跳过错误节点剩余内容,避免影响后续字段解析 jp.skipChildren() } } }
2. 定义启用容错的标记注解
import com.fasterxml.jackson.annotation.JacksonAnnotation import kotlin.annotation.AnnotationTarget.* @Target(FIELD, VALUE_PARAMETER, PROPERTY_GETTER) @Retention(AnnotationRetention.RUNTIME) @JacksonAnnotation annotation class DeserializeNullOnError
3. 注册到Jackson全局配置
import com.fasterxml.jackson.databind.Module import com.fasterxml.jackson.databind.deser.Deserializers import com.fasterxml.jackson.databind.module.SimpleModule import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration class JacksonCustomConfig { @Bean fun nullOnErrorDeserializationModule(): Module { return SimpleModule().apply { addDeserializers(object : Deserializers.Base() { override fun findBeanDeserializer( type: JavaType, config: com.fasterxml.jackson.databind.DeserializationConfig, beanDesc: com.fasterxml.jackson.databind.BeanDescription ) = if (beanDesc.annotated.hasAnnotation(DeserializeNullOnError::class.java)) { NullOnErrorDeserializer(type) } else null }) } } }
4. 使用示例
在需要开启容错的可空字段上添加注解即可,所有子对象类型可通用:
data class FooDTO( @DeserializeNullOnError val bar: BarDTO?, @DeserializeNullOnError val other: OtherDTO?, // 其他子对象直接加注解即可复用逻辑 val name: String )
方案2:全局自动容错(省事)
适合所有可空子对象都需要容错的场景,无需修改现有DTO代码,全局生效。
直接注册自定义异常处理器到Jackson配置即可:
import com.fasterxml.jackson.core.JsonParser import com.fasterxml.jackson.databind.DeserializationContext import com.fasterxml.jackson.databind.deser.DeserializationProblemHandler import com.fasterxml.jackson.databind.module.SimpleModule import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration @Configuration class JacksonLenientConfig { @Bean fun globalLenientModule(): SimpleModule { return SimpleModule().apply { addHandler(object : DeserializationProblemHandler() { // 处理类型不匹配的异常 override fun handleUnexpectedToken( ctxt: DeserializationContext, targetType: Class<*>, token: com.fasterxml.jackson.core.JsonToken, p: JsonParser, failureMsg: String? ): Any? { return if (!targetType.isPrimitive) { p.skipChildren() null } else super.handleUnexpectedToken(ctxt, targetType, token, p, failureMsg) } // 处理字符串转对象的异常 override fun handleWeirdStringValue( ctxt: DeserializationContext, targetType: Class<*>, value: String, failureMsg: String? ): Any? { return if (!targetType.isPrimitive && targetType != String::class.java) { null } else super.handleWeirdStringValue(ctxt, targetType, value, failureMsg) } }) } } }
内容的提问来源于stack exchange,提问作者TovrikTheThird
相关产品推荐
相关产品推荐

