使用Jackson注解映射JSON键至Scala Case Class属性反序列化报错
问题分析与解决方案
错误原因
你遇到的问题核心是混用了Jackson注解与json4s库:代码里使用json4s.Serialization.read进行反序列化,但给Case Class加的是Jackson的@JsonProperty/@JsonAlias注解——json4s无法识别这些Jackson专属注解,因此无法将JSON中的ageInInt字段映射到Case Class的age属性,最终抛出找不到age值的异常。
解决方案
根据你的需求,提供两种可行方案:
方案1:继续使用json4s(适配现有代码栈)
利用json4s自身的字段映射机制实现字段重命名,无需依赖Jackson注解。
方式A:自定义Format
直接实现json4s的Format trait,手动控制字段读写逻辑:
import org.json4s._ import org.json4s.jackson.Serialization case class Person(name: String, age: Int) val json = """{ |"name": "Tausif", |"ageInInt": 30 |}""".stripMargin // 自定义Person的Format implicit val personFormat: Format[Person] = new Format[Person] { override def reads(json: JValue): Person = { Person( name = (json \ "name").extract[String], age = (json \ "ageInInt").extract[Int] ) } override def writes(person: Person): JValue = { JObject( "name" -> JString(person.name), "ageInInt" -> JInt(person.age) ) } } // 反序列化 println(Serialization.read[Person](json))
方式B:使用FieldSerializer
通过json4s的FieldSerializer快速实现字段重命名,代码更简洁:
import org.json4s._ import org.json4s.jackson.Serialization import org.json4s.FieldSerializer._ case class Person(name: String, age: Int) val json = """{ |"name": "Tausif", |"ageInInt": 30 |}""".stripMargin // 配置字段映射:将age <-> ageInInt互转 implicit val format: DefaultFormats.type = DefaultFormats + FieldSerializer[Person]( renameTo("age", "ageInInt"), // 序列化时把age转成ageInInt renameFrom("ageInInt", "age") // 反序列化时把ageInInt转成age ) // 反序列化 println(Serialization.read[Person](json))
方案2:切换为Jackson Scala模块(保留Jackson注解)
如果想继续使用Jackson注解,需改用Jackson官方的Scala模块完成反序列化:
- 确保依赖中包含
jackson-module-scala(比如sbt依赖:"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.15.2") - 使用Jackson的
ObjectMapper并注册Scala模块:
import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.module.scala.DefaultScalaModule import com.fasterxml.jackson.annotation.JsonProperty case class Person(name: String, @JsonProperty("ageInInt") age: Int) val json = """{ |"name": "Tausif", |"ageInInt": 30 |}""".stripMargin // 初始化Jackson ObjectMapper并注册Scala模块 val mapper = new ObjectMapper() mapper.registerModule(DefaultScalaModule) // 反序列化 val person = mapper.readValue(json, classOf[Person]) println(person)
内容的提问来源于stack exchange,提问作者Tausif Sayyad
相关产品推荐
相关产品推荐

