Play Framework 2.6.x中Scala Map转Json报错求助
解决Play Framework 2.6.x中Map[String, Object]转Json的序列化问题
兄弟我懂你踩的这两个坑,Play Framework的Json序列化对这种宽泛的Map[String, Object]确实不友好,我来给你捋清楚问题根源,再给你靠谱的解决方案:
先说说你之前报错的原因
- 第一次报错是因为Play的Json库默认没有
Map[String, Object]的序列化器——毕竟Object是个超级宽泛的类型,框架没法自动推断里面藏着什么类型的数据,自然找不到对应的序列化逻辑。 - 第二次用
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
相关产品推荐
相关产品推荐

