Scala中Jackson转换含空字符串JSON至Case Class时抛出异常求助
我之前也碰到过一模一样的坑!当JSON里的空字符串对应Case Class的非String类型字段时,Jackson完全不知道该怎么处理,直接就抛出实例化失败的异常。下面给你几个实用的解决方案,你可以根据自己的场景来选:
方案1:给Case Class字段加默认值 + 配置Jackson参数
这是最省心的方案,适合大多数常规场景。
首先,给你的Case Class字段加上默认值,这样当Jackson遇到无法解析的空字符串时,可以自动用默认值填充:
case class Person(id: Int = 0, name: String = "")
然后配置你的Jackson ObjectMapper,开启两个关键参数:
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.databind.DeserializationFeature val mapper = new ObjectMapper() // 必须注册Scala模块,不然Jackson没法正确识别Case Class .registerModule(DefaultScalaModule) // 把空字符串当作null来处理 .configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true) // 允许基本类型接收null(会自动用字段默认值填充) .configure(DeserializationFeature.FAIL_ON_NULL_FOR_PRIMITIVES, false)
这样配置后,当JSON里的id是空字符串时,Jackson会把它转成null,然后自动用Case Class里的默认值0来实例化Person对象,就不会再报错了。
方案2:自定义反序列化器(针对特定类型)
如果你的需求更个性化(比如空字符串要转成特定值,不是通用默认值),可以写一个自定义反序列化器。
比如针对Int类型,写一个把空字符串转成你想要的值的反序列化器:
import com.fasterxml.jackson.databind.{DeserializationContext, JsonDeserializer} import com.fasterxml.jackson.core.JsonParser class EmptyStringToIntDeserializer extends JsonDeserializer[Int] { override def deserialize(p: JsonParser, ctxt: DeserializationContext): Int = { val input = p.getText.trim // 这里把空字符串转成-1,你可以改成任何你需要的默认值 if (input.isEmpty) -1 else input.toInt } }
然后在Case Class的对应字段上标注使用这个反序列化器:
import com.fasterxml.jackson.databind.annotation.JsonDeserialize case class Person( @JsonDeserialize(using = classOf[EmptyStringToIntDeserializer]) id: Int, name: String )
这样不管JSON里的id是空字符串还是正常数字,都能正确解析成Int类型,不会抛出异常。
方案3:全局配置空字符串转null(覆盖所有类型)
如果你想让Jackson全局把所有空字符串都转成null,而不是针对单个类型配置,只需要在ObjectMapper里加上这个参数:
mapper.configure(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT, true)
配合Case Class的默认值使用,就能覆盖大部分场景了。
为什么会报错?
简单来说:Jackson默认不会把空字符串自动转成null或者对应类型的默认值,当它尝试把空字符串赋值给Case Class的非String字段(比如Int)时,类型转换失败,再加上Case Class的字段没有默认值的话,没法实例化对象,就会抛出JsonMappingException。
内容的提问来源于stack exchange,提问作者user3407267

