如何在Scala/Play/JSON中正确创建兼容编解码的OFormat?
问题分析与解决方案
错误原因
编码时抛出的java.lang.RuntimeException: when empty JsPath, expecting JsObject,核心问题是写入器(OWrites)未绑定到当前的JsPath。你在forceFormatNullableInt中使用了全局的JsPath.writeNullable[Int],这是一个未关联具体路径的写入器,和绑定了路径的Reads组合成OFormat后,编码阶段无法找到正确的字段路径写入值,从而触发异常。
修复后的代码
只需将OFormat中的写入器替换为基于当前jsPath的writeNullable实现即可:
package object Example { implicit class JsPathOps(jsPath: JsPath) { def forceReadNullableInt: Reads[Option[Int]] = jsPath.readNullable[Int] or jsPath.readNullable[String] .map(_.flatMap(string => Try(string.toInt).toOption)) def forceFormatNullableInt: OFormat[Option[Int]] = // 关键修改:使用当前jsPath的writeNullable,而非全局的JsPath.writeNullable OFormat(forceReadNullableInt, jsPath.writeNullable[Int]) } }
验证与补充
修改后运行测试代码,编码逻辑会正常工作:
- 当
age为None时,JSON中不会包含该字段 - 当
age为Some(Int)时,会以整数类型输出该字段值
如果想要让输出的JSON格式化与输入完全匹配(包括空格),可以用Json.prettyPrint替代toString:
val json1out: String = Json.prettyPrint(Json.toJson(user1)) val json2out: String = Json.prettyPrint(Json.toJson(user2))
你的自定义解码器已经正确覆盖了四种场景:字段缺失、字段为整数、字段为字符串形式整数、字段为随机字符串,修复后的编码器会与之对应,保持输入输出的格式一致性。
内容的提问来源于stack exchange,提问作者DCameronMauch
相关产品推荐
相关产品推荐

