You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

json4s部分反序列化问题:JSON对象与Person样例类字段不匹配

解决JSON对象数组与Scala样例类字符串序列的序列化适配问题

你遇到的是JSON结构与Scala样例类字段类型不匹配的典型问题:JSON里的addresses是包含street和apt的对象数组,但你的Person样例类把这个字段定义成了Option[Seq[String]],默认序列化器没法自动完成这种类型转换,导致反序列化/序列化失败。下面基于你提到的json4s(Serialization.form属于该库)给出完整解决方案:


核心思路:自定义序列化器

我们需要实现一个自定义序列化器,手动处理Seq[String](及包装它的Option)和JSON对象数组之间的双向转换:

  1. 反序列化:把每个JSON地址对象转换成你需要的字符串格式(比如拼接street和apt,或直接转成JSON字符串)
  2. 序列化:把字符串再转回原来的JSON地址对象结构(保证双向转换的一致性)

完整代码实现

1. 导入依赖与包

先确保项目引入json4s的jackson模块(比如sbt依赖:"org.json4s" %% "json4s-jackson" % "4.0.6"),然后导入相关包:

import org.json4s._
import org.json4s.JsonDSL._
import org.json4s.jackson.Serialization
import org.json4s.jackson.Serialization.{read, write}

2. 保留原有样例类

保持你定义的Person样例类不变:

case class Person(
  name: Option[String] = None,
  addresses: Option[Seq[String]] = Some(Seq.empty)
)

3. 实现自定义序列化器

这里我们把每个地址对象拼接成"街道, 公寓号"的格式,你可以根据需求调整字符串规则:

class AddressesSerializer extends CustomSerializer[Seq[String]](format => (
  // 反序列化:JSON数组 → 字符串序列
  {
    case JArray(addressObjs) =>
      addressObjs.map {
        // 解析每个地址对象的street和apt字段
        case JObject(fields) =>
          val street = fields.find(_._1 == "street").map(_._2.extract[String]).getOrElse("")
          val apt = fields.find(_._1 == "apt").map(_._2.extract[String]).getOrElse("")
          s"$street, Apt $apt" // 自定义字符串格式
        // 处理非预期的JSON类型
        case _ => ""
      }
    // 处理JSON中addresses为null的情况
    case JNull => Seq.empty
  },
  // 序列化:字符串序列 → JSON数组
  {
    case addresses: Seq[String] =>
      JArray(addresses.map { addrStr =>
        // 根据反序列化的格式拆分字符串,还原成地址对象
        val parts = addrStr.split(", Apt ")
        val street = if (parts.length > 0) parts(0) else ""
        val apt = if (parts.length > 1) parts(1) else ""
        // 构建JSON对象
        ("street" -> street) ~ ("apt" -> apt)
      })
  }
))

4. 配置格式并测试

把自定义序列化器加入formats配置,然后测试双向转换:

// 配置formats,加入自定义序列化器,关闭类型提示
implicit val formats: Formats = Serialization.formats(NoTypeHints) + new AddressesSerializer

// 测试用JSON字符串
val jsonStr = """{ "name": "Chaitanya", "addresses": [ { "street": "20 ABC", "apt": "10" }, { "street": "10 XYZ", "apt": "D3" } ] }"""

// 反序列化JSON到Person对象
val person: Person = read[Person](jsonStr)
println(person)
// 输出:Person(Some(Chaitanya),Some(List(20 ABC, Apt 10, 10 XYZ, Apt D3)))

// 序列化Person对象回JSON
val serializedJson = write(person)
println(serializedJson)
// 输出:{"name":"Chaitanya","addresses":[{"street":"20 ABC","apt":"10"},{"street":"10 XYZ","apt":"D3"}]}

关键说明

  • 如果不需要把字符串序列回原JSON结构,可以只实现反序列化逻辑,但建议保持双向一致性,避免后续问题。
  • json4s会自动处理Option类型:若JSON中addresses缺失或为null,会自动映射为None;样例类的默认值Some(Seq.empty)也会正常生效。
  • 你可以根据业务需求调整字符串转换格式,比如把地址对象直接转成JSON字符串(用write(JObject(fields))),这样后续还原时更准确。

内容的提问来源于stack exchange,提问作者Chaitanya Chandurkar

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:13:15