Play Framework 2.8.2 - 未找到类型(子类)的 Json 序列化程序
Play Framework 2.8.2 - No Json serializer found for type (subclass)
我正在将我的一些服务从 Play 2.7.x 迁移到最新的 2.8.2,以及 scala 2.13.2 和 sbt 1.3.12。
不过我遇到了游戏障碍-json,Reads[A]
我有以下设置:
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val writes: Writes[Charge] = (charge: Charge) => {...}
}
我们有一些测试看起来像这样
val chargeOne = ChargeOne(1)
val json = Json.toJson(charge)
json mustBe "..."
并且这些在 play 2.7.x 和 scala 2.12.x 中工作正常,它也适用于 scala 2.13.2,但是在将 play 升级到 2.8.2 之后,以下编译时出现错误:
No Json serializer found for type ChargeOne. Try to implement an implicit Writes or Format for this type.
而且我必须将 .asInstanceOf[Charge]
添加到我的测试中才能使其正常工作。
这里发生了什么?是play-json吗?还是scala?有谁知道如何“修复”它?
如错误消息中所示,需要 ChargeOne
的 Writes
(或 Format
)实例,而代码仅提供 Reads
。
import play.api.libs.json._ // BTW Recommend to provide import in code examples
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val format: OFormat[Charge] = {
// Need to define instance for the subtypes (no auto-materialization)
implicit def one = Json.format[ChargeOne]
implicit def two = Json.format[ChargeTwo]
Json.format[Charge]
}
}
然后你可以看到 Writes
和 Reads
是不变的(类型类)所以只解析父类型 Charge
:
scala> Json.toJson(ChargeOne(1))
<console>:17: error: No Json serializer found for type ChargeOne. Try to implement an implicit Writes or Format for this type.
Json.toJson(ChargeOne(1))
^
scala> Json.toJson(ChargeOne(1): Charge)
res1: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
如果您不想在每个 toJson
上添加注释:
import play.api.libs.json._ // BTW Recommend to provide import in code examples
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val format: OFormat[Charge] = {
// Need to define instance for the subtypes (no auto-materialization)
implicit def one = Json.format[ChargeOne]
implicit def two = Json.format[ChargeTwo]
Json.format[Charge]
}
implicit def genericWrites[T <: Charge]: OWrites[T] =
format.contramap[T](c => c: Charge)
implicit def genericReads[T <: Charge](implicit evidence: scala.reflect.ClassTag[T]): Reads[T] = format.collect[T](JsonValidationError(s"Type mismatch: ${evidence.runtimeClass.getName}")) {
case `evidence`(t) => t
}
}
scala> Json.toJson(ChargeOne(1))
res0: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
scala> Json.toJson(ChargeOne(1)).validate[Charge]
res0: play.api.libs.json.JsResult[Charge] = JsSuccess(ChargeOne(1),)
注意#1:重要的是要看到(反)序列化 ChargeOne
(或任何子类型)作为 Charge
(或任何类似的父类型) to/from JSON 与“直接”执行不同。 JSON 表示与密封家族序列化不同,需要鉴别器 JSON 字段(参见 _type
)。
scala> Json.writes[ChargeOne].writes(ChargeOne(1))
res1: play.api.libs.json.JsObject = {"one":1}
scala> Json.toJson(ChargeOne(1)) // .. as Charge parent type
res2: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
注意#2:如果一些类似的用例在以前的版本中错误地工作,它会导致难以预测的 JSON 表示,以及关键的隐式解析很多情况下,这就是这种行为的原因 change/fix(参见 pull request)。
我正在将我的一些服务从 Play 2.7.x 迁移到最新的 2.8.2,以及 scala 2.13.2 和 sbt 1.3.12。
不过我遇到了游戏障碍-json,Reads[A]
我有以下设置:
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val writes: Writes[Charge] = (charge: Charge) => {...}
}
我们有一些测试看起来像这样
val chargeOne = ChargeOne(1)
val json = Json.toJson(charge)
json mustBe "..."
并且这些在 play 2.7.x 和 scala 2.12.x 中工作正常,它也适用于 scala 2.13.2,但是在将 play 升级到 2.8.2 之后,以下编译时出现错误:
No Json serializer found for type ChargeOne. Try to implement an implicit Writes or Format for this type.
而且我必须将 .asInstanceOf[Charge]
添加到我的测试中才能使其正常工作。
这里发生了什么?是play-json吗?还是scala?有谁知道如何“修复”它?
如错误消息中所示,需要 ChargeOne
的 Writes
(或 Format
)实例,而代码仅提供 Reads
。
import play.api.libs.json._ // BTW Recommend to provide import in code examples
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val format: OFormat[Charge] = {
// Need to define instance for the subtypes (no auto-materialization)
implicit def one = Json.format[ChargeOne]
implicit def two = Json.format[ChargeTwo]
Json.format[Charge]
}
}
然后你可以看到 Writes
和 Reads
是不变的(类型类)所以只解析父类型 Charge
:
scala> Json.toJson(ChargeOne(1))
<console>:17: error: No Json serializer found for type ChargeOne. Try to implement an implicit Writes or Format for this type.
Json.toJson(ChargeOne(1))
^
scala> Json.toJson(ChargeOne(1): Charge)
res1: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
如果您不想在每个 toJson
上添加注释:
import play.api.libs.json._ // BTW Recommend to provide import in code examples
sealed trait Charge {}
case class ChargeOne(one: Int) extends Charge
case class ChargeTwo(two: Int) extends Charge
object Charge {
implicit val format: OFormat[Charge] = {
// Need to define instance for the subtypes (no auto-materialization)
implicit def one = Json.format[ChargeOne]
implicit def two = Json.format[ChargeTwo]
Json.format[Charge]
}
implicit def genericWrites[T <: Charge]: OWrites[T] =
format.contramap[T](c => c: Charge)
implicit def genericReads[T <: Charge](implicit evidence: scala.reflect.ClassTag[T]): Reads[T] = format.collect[T](JsonValidationError(s"Type mismatch: ${evidence.runtimeClass.getName}")) {
case `evidence`(t) => t
}
}
scala> Json.toJson(ChargeOne(1))
res0: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
scala> Json.toJson(ChargeOne(1)).validate[Charge]
res0: play.api.libs.json.JsResult[Charge] = JsSuccess(ChargeOne(1),)
注意#1:重要的是要看到(反)序列化 ChargeOne
(或任何子类型)作为 Charge
(或任何类似的父类型) to/from JSON 与“直接”执行不同。 JSON 表示与密封家族序列化不同,需要鉴别器 JSON 字段(参见 _type
)。
scala> Json.writes[ChargeOne].writes(ChargeOne(1))
res1: play.api.libs.json.JsObject = {"one":1}
scala> Json.toJson(ChargeOne(1)) // .. as Charge parent type
res2: play.api.libs.json.JsValue = {"one":1,"_type":"ChargeOne"}
注意#2:如果一些类似的用例在以前的版本中错误地工作,它会导致难以预测的 JSON 表示,以及关键的隐式解析很多情况下,这就是这种行为的原因 change/fix(参见 pull request)。