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

Play Framework 2.6.x中Scala Map转Json报错求助

解决Play Framework 2.6.x中Map[String, Object]转Json的序列化问题

兄弟我懂你踩的这两个坑,Play Framework的Json序列化对这种宽泛的Map[String, Object]确实不友好,我来给你捋清楚问题根源,再给你靠谱的解决方案:

先说说你之前报错的原因

  1. 第一次报错是因为Play的Json库默认没有Map[String, Object]的序列化器——毕竟Object是个超级宽泛的类型,框架没法自动推断里面藏着什么类型的数据,自然找不到对应的序列化逻辑。
  2. 第二次用Json.writes[Map[String, Object]]不行,是因为这个宏只给case class生成序列化器,Map是集合类型,根本没有case class的apply方法,所以肯定会报找不到apply的错误。

正确解决方案:自定义递归序列化器

我们需要自己写一个能处理Object(Scala里本质等同于Any)的序列化器,用模式匹配覆盖常见的数据类型,甚至支持嵌套的集合结构。直接上可用代码:

def toJson(x: Map[String, Object]) = {
  import play.api.libs.json._

  // 定义一个能处理任意类型的Writes,递归处理嵌套结构
  implicit val anyWrites: Writes[Any] = new Writes[Any] {
    override def writes(value: Any): JsValue = value match {
      // 处理基本数据类型
      case s: String => JsString(s)
      case i: Int => JsNumber(i)
      case l: Long => JsNumber(l)
      case d: Double => JsNumber(d)
      case b: Boolean => JsBoolean(b)
      // 处理嵌套的Map
      case nestedMap: Map[String, _] => 
        Json.toJson(nestedMap)(Writes.mapWrites(anyWrites))
      // 处理List和Array集合
      case list: List[_] => 
        Json.toJson(list)(Writes.listWrites(anyWrites))
      case array: Array[_] => 
        Json.toJson(array)(Writes.arrayWrites(anyWrites))
      // 处理null值
      case null => JsNull
      // 兜底逻辑:未知类型转成字符串,避免序列化失败
      case unknown => JsString(unknown.toString)
    }
  }

  // 用上面的anyWrites作为Map值的序列化器,完成转换
  Json.toJson(x)(Writes.mapWrites(anyWrites))
}

代码逻辑解释

  • 递归处理嵌套结构:不管你的Map里嵌套了多少层Map、List,这个序列化器都能递归解析,生成标准的结构化Json。
  • 兜底容错:遇到框架没覆盖的自定义类型时,会自动转成字符串,不会直接抛出异常,保证序列化过程能正常完成。
  • 为什么不用自动生成的Writes:Play的Json.writes宏是专门为case class设计的,集合类型完全不适用,所以必须手动实现针对Any的序列化逻辑。

测试示例

你可以用下面的代码验证效果:

val testData = Map(
  "username" -> "worldterminator".asInstanceOf[Object],
  "age" -> 28.asInstanceOf[Object],
  "isVerified" -> true.asInstanceOf[Object],
  "hobbies" -> List("coding", "hiking").asInstanceOf[Object],
  "contact" -> Map("email" -> "test@example.com", "phone" -> "123456").asInstanceOf[Object]
)

println(toJson(testData))

输出的标准Json格式如下:

{
  "username": "worldterminator",
  "age": 28,
  "isVerified": true,
  "hobbies": ["coding", "hiking"],
  "contact": {"email": "test@example.com", "phone": "123456"}
}

额外提示

如果你的Object里包含自定义的case class,记得在模式匹配里加上对应的分支,比如:

case customObj: YourCustomCaseClass => Json.toJson(customObj)

前提是你的YourCustomCaseClass已经有对应的Writes(可以用Json.writes[YourCustomCaseClass]自动生成)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 10:18:20