Jackson缺失属性时设0而非抛异常的全局配置诉求
Jackson全局配置:缺失必填基本类型属性时触发反序列化失败
问题场景
请求JSON示例:
{ "name" : "test" }
对应的Kotlin数据类:
data class DTO(val name: String, val maxValue: Long)
当前问题:Jackson会自动将缺失的maxValue设为0,但实际需要全局配置让所有缺失的基本类型属性触发反序列化失败,且不接受@JsonProperty(required = true)这类局部注解方案;之前尝试的DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES仅对显式传入null的情况生效,对属性缺失场景无效。
解决方案
Jackson没有直接的全局开关实现这个需求,但可以通过自定义BeanDeserializerModifier来全局校验所有基本类型属性的存在性:
1. 实现自定义BeanDeserializerModifier
这个类会在反序列化完成后,检查所有基本类型字段是否是因属性缺失而保留默认值:
import com.fasterxml.jackson.databind.BeanDescription import com.fasterxml.jackson.databind.DeserializationConfig import com.fasterxml.jackson.databind.JsonDeserializer import com.fasterxml.jackson.databind.deser.BeanDeserializer import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier import com.fasterxml.jackson.databind.exc.MismatchedInputException import java.lang.reflect.Field class RequiredPrimitiveModifier : BeanDeserializerModifier() { override fun modifyDeserializer( config: DeserializationConfig, beanDesc: BeanDescription, deserializer: JsonDeserializer<*> ): JsonDeserializer<*> { if (deserializer is BeanDeserializer) { return object : BeanDeserializer(deserializer) { override fun deserialize(p: com.fasterxml.jackson.databind.JsonParser, ctxt: com.fasterxml.jackson.databind.DeserializationContext): Any { val bean = super.deserialize(p, ctxt) // 遍历所有基本类型字段,校验是否因属性缺失导致使用默认值 bean::class.java.declaredFields.forEach { field -> field.isAccessible = true if (field.type.isPrimitive) { val defaultValue = when (field.type) { Long::class.javaPrimitiveType -> 0L Int::class.javaPrimitiveType -> 0 Boolean::class.javaPrimitiveType -> false // 可根据需求扩展其他基本类型(如Short、Byte等) else -> null } defaultValue?.let { default -> if (field.get(bean) == default) { // 检查JSON中是否存在该属性 val parsedJson = p.parsedObject if (!parsedJson.has(field.name)) { throw MismatchedInputException.from( p, "Required primitive property '${field.name}' is missing from JSON", p.currentToken, beanDesc.beanClass ) } } } } } return bean } } } return deserializer } }
2. 注册到ObjectMapper
将自定义的Modifier注册到全局的ObjectMapper实例中:
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.kotlin.registerKotlinModule val globalObjectMapper = ObjectMapper().apply { // 注册Kotlin模块,支持Kotlin数据类序列化/反序列化 registerKotlinModule() // 注册自定义的校验模块 registerModule(object : com.fasterxml.jackson.databind.Module() { override fun getModuleName() = "RequiredPrimitiveValidationModule" override fun setupModule(context: com.fasterxml.jackson.databind.Module.SetupContext) { context.addBeanDeserializerModifier(RequiredPrimitiveModifier()) } }) }
3. 验证效果
- 当反序列化缺失
maxValue的JSON时,会抛出MismatchedInputException,提示属性缺失 - 若JSON中显式传入
maxValue: 0,则可以正常完成反序列化,不会触发异常
补充说明
- 该方案会全局作用于所有基本类型字段,无需逐个添加注解
- 如果需要排除特定字段,可以自定义一个注解(如
@OptionalPrimitive),然后在Modifier中判断字段是否带有该注解,跳过校验 - 针对Kotlin数据类,Jackson通过构造器注入属性值,反射检查字段默认值的方式可以准确区分“显式传入默认值”和“属性缺失”两种情况
内容的提问来源于stack exchange,提问作者Dmitry Morozov
相关产品推荐
相关产品推荐

