如何在 Scala 中将特征序列化和反序列化到 Json 或从 Json 反序列化?
How to serialize and deserialize traits, to and from Json, in Scala?
第一次尝试:
到目前为止我已经尝试过喷雾-json。我有:
trait Base
case class A ( id: String) extends Base
case class B (id: String) extends Base
现在,为了序列化和反序列化我的 Base
类型,我有代码:
implicit object BaseFormat extends RootJsonFormat[Base]{
def write(obj: Base): JsValue = {
obj match {
case a: A => a.toJson
case b: B => b.toJson
case unknown @ _ => serializationError(s"Marshalling issue with ${unknown}")
}
}
def read(json: JsValue): Base = {
//how to know whether json is encoding an A or a B?
}
}
问题是,为了实现反序列化的 read
方法,我想不出一种方法来知道 JsValue 编码的是 A
还是 B
.
第二次尝试:
为了在 spray-json
中解决这个问题,我最终只是将 A
中的字段 id
重命名为 aID
,并将 B
中的字段重命名为 bID
.
第三次尝试:
由于 spray-json
不如 zio-json
或 circe
等替代库复杂,它们无需额外代码即可自行处理此问题,因此我开始使用 zio-json
现在我得到了错误
magnolia: could not infer DeriveJsonEncoder.Typeclass for type
对于所有情况 类 采用类型参数。
此外,它在链式特征继承方面存在问题。似乎 circe 也使用木兰。所以这很可能也会被 circe 复制。
如有任何帮助,我们将不胜感激。
您应该使用 json encoding/decoding 库解决这个问题。
这是一个使用 circe 的例子,它是半自动模式。
既然你在评论中提到你在你的案例中遇到泛型类型问题 classes,我也把它包括在内。基本上,要为包含 T
的 class Foo[T]
导出编码器或解码器,您必须证明存在编码和解码 T
的方法。这是通过请求一个隐式的 Encoder[T]
和 Decoder[T]
来完成的,您可以在其中导出 Encoder[Foo[T]]
和 Decoder[Foo[T]]
。当然,您可以将此推理概括为适用于多个泛型类型,您只需要隐含地使用一对 encoder/decoder,在其中为相应的情况 class 派生 encoder/decoder。
import io.circe._, io.circe.generic.semiauto._, io.circe.syntax._
case class Foo[T](a: Int, b: String, t: T)
object Foo {
implicit def decoder[T: Encoder: Decoder]: Decoder[Foo[T]] = deriveDecoder
implicit def encoder[T: Encoder: Decoder]: Encoder[Foo[T]] = deriveEncoder
}
case class Bar(a: Int)
object Bar {
implicit val encoder: Encoder[Bar] = deriveEncoder
implicit val decoder: Decoder[Bar] = deriveDecoder
}
case class Baz(a: Int)
println(Foo(42, "hello", 23.4).asJson) // Works because circe knows Encoder[Float]
println(Foo(42, "hello", Bar(42)).asJson) // Works because we defined Encoder[Bar]
//println(Foo(42, "hello", Baz(42)).asJson) // Doesn't compile: circe doesn't know Encoder[Baz] in semi-auto mode
请注意,需要为您使用的每种类型 T
生成 Foo[T]
的不同 encoder/decoder,这就是 [=21= 的编码器和解码器派生的原因] 必须是方法,而不是像 Bar
.
这样的值
还有一个全自动模式,但它往往会产生编译时错误,对于初学者来说更难调试,所以我会从半自动开始。另一个问题是,自动模式在大型项目上编译可能需要更长的时间。如果你喜欢冒险,不犯错就更美了!
import io.circe._, io.circe.generic.auto._, io.circe.syntax._
case class Foo[T](a: Int, b: String, t: T)
case class Bar(a: Int)
case class Baz(a: Int)
println(Foo(42, "hello", 23.4).asJson) // circe knows Encoder[Float] and automatically derives Encoder[Foo[Float]]
println(Foo(42, "hello", Bar(42)).asJson) // circe wants Encoder[Foo[Bar]], so it ma(cro)gically derives Encoder[Bar] and then Encoder[Foo[Bar]]
println(Foo(42, "hello", Baz(42)).asJson) // Does compile this time, circe automatically find the encoder/decoder for Baz the same way it does for Bar
一个有效的 example 将 traits 与泛型结合使用是这样的:
import io.circe.Decoder.Result
import io.circe._
import io.circe.generic.semiauto._
import io.circe.syntax._
trait MyBase[T <: MyBase[T]] {
def myid: String
def issue: MyBaseIssue
def summary: MyBaseSummary[T]
}
trait MyBaseIssue
object MyBaseIssue {
implicit val decodeIssue: Decoder[MyBaseIssue] =
Decoder[SimpleBaseIssue].map[MyBaseIssue](identity).or(
Decoder[SophisticatedBaseIssue].map[MyBaseIssue](identity)
)
implicit val encodeIssue: Encoder[MyBaseIssue] = Encoder.instance {
case simple @ SimpleBaseIssue(_) => simple.asJson
case sophisticated @ SophisticatedBaseIssue(_) => sophisticated.asJson
}
}
trait MyBaseSummary[T <: MyBase[T]]
object MyBaseSummary {
implicit def decodeSummary[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseSummary[T]] =
Decoder[SimpleBaseSummary].map[MyBaseSummary[SimpleBase]](identity).asInstanceOf[Decoder[MyBaseSummary[T]]].or(
Decoder[SophisticatedBaseSummary].map[MyBaseSummary[SophisticatedBase]](identity).asInstanceOf[Decoder[MyBaseSummary[T]]]
)
implicit def encodeSummary[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseSummary[T]] = Encoder.instance {
case simple @ SimpleBaseSummary(_) => simple.asJson
case sophisticated @ SophisticatedBaseSummary(_) => sophisticated.asJson
}
}
case class SimpleBase(
myid: String,
override val issue: SimpleBaseIssue,
override val summary: SimpleBaseSummary
) extends MyBase[SimpleBase]
case class SophisticatedBase(
myid: String,
extraField: String,
override val issue: SophisticatedBaseIssue,
override val summary: SophisticatedBaseSummary
) extends MyBase[SophisticatedBase]
object SimpleBase {
implicit val encoder: Encoder[SimpleBase] = deriveEncoder
implicit val decoder: Decoder[SimpleBase] = deriveDecoder
}
object SophisticatedBase {
implicit val encoder: Encoder[SophisticatedBase] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBase] = deriveDecoder
}
case class SimpleBaseIssue(simpleIssueType: String) extends MyBaseIssue
case class SophisticatedBaseIssue(sophisticatedIssueType: String) extends MyBaseIssue
object SimpleBaseIssue {
implicit val encoder: Encoder[SimpleBaseIssue] = deriveEncoder
implicit val decoder: Decoder[SimpleBaseIssue] = deriveDecoder
}
object SophisticatedBaseIssue {
implicit val encoder: Encoder[SophisticatedBaseIssue] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBaseIssue] = deriveDecoder
}
case class SimpleBaseSummary(simpleSummary: String) extends MyBaseSummary[SimpleBase]
case class SophisticatedBaseSummary(sophisticatedSummary: String) extends MyBaseSummary[SophisticatedBase]
object SimpleBaseSummary {
implicit val encoder: Encoder[SimpleBaseSummary] = deriveEncoder
implicit val decoder: Decoder[SimpleBaseSummary] = deriveDecoder
}
object SophisticatedBaseSummary {
implicit val encoder: Encoder[SophisticatedBaseSummary] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBaseSummary] = deriveDecoder
}
case class MyBaseList[T <: MyBase[T]](
myid: String,
var membersMap: Map[String, T] = Map.empty,
override val issue: MyBaseListIssues[T],
override val summary: MyBaseListSummary[T]
) extends MyBase[MyBaseList[T]]
object MyBaseList {
implicit def membersMapDecoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[Map[String, T]] = Decoder.decodeMap
implicit def membersMapEncoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[Map[String, T]] = Encoder.encodeMap
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseList[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseList[T]] = deriveDecoder
}
case class MyBaseListIssues[T <: MyBase[T]](
issue: String,
var set: Set[MyBaseIssue] = Set[MyBaseIssue]()
) extends MyBaseIssue
object MyBaseListIssues {
implicit def membersMapDecoder: Decoder[Set[MyBaseIssue]] =
Decoder.decodeSet[MyBaseIssue]
implicit def membersMapEncoder: Encoder[Set[MyBaseIssue]] = Encoder.encodeSet
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseListIssues[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseListIssues[T]] = deriveDecoder
}
case class MyBaseListSummary[T <: MyBase[T]](
summaryList: Map[String, MyBaseSummary[T]]
) extends MyBaseSummary[MyBaseList[T]]
object MyBaseListSummary {
implicit def membersMapDecoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[Map[String, MyBaseSummary[T]]] = Decoder.decodeMap
implicit def membersMapEncoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[Map[String, MyBaseSummary[T]]] = Encoder.encodeMap
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseListSummary[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseListSummary[T]] = deriveDecoder
}
object MainObject extends App {
val simpleList = MyBaseList[SimpleBase]("simpleId",
Map("one" -> SimpleBase("baseid", SimpleBaseIssue("the mistake"), SimpleBaseSummary("very concise"))),
MyBaseListIssues[SimpleBase]("listIssue", Set(SimpleBaseIssue("a disaster"))),
MyBaseListSummary[SimpleBase]( Map("simplebaseid" -> SimpleBaseSummary("super concise")))
)
val simpleJson = simpleList.asJson
println(simpleJson)
val convertedSimpleList = simpleJson.as[MyBaseList[SimpleBase]]
println(convertedSimpleList)
val sphisticatedList = MyBaseList[SophisticatedBase]("sophisticatedId",
Map("one" -> SophisticatedBase("baseid", "further detail", SophisticatedBaseIssue("the mistake"), SophisticatedBaseSummary("very concise"))),
MyBaseListIssues[SophisticatedBase]("listIssue", Set(SophisticatedBaseIssue("a disaster"))),
MyBaseListSummary[SophisticatedBase]( Map("sophisticatedbaseid" -> SophisticatedBaseSummary("super concise")))
)
val sophisticatedJson = sphisticatedList.asJson
println(sophisticatedJson)
val convertedSophisticatedListDecoder: Result[MyBaseList[SophisticatedBase]] = sophisticatedJson.as[MyBaseList[SophisticatedBase]]
println(convertedSophisticatedListDecoder)
convertedSophisticatedListDecoder match {
case Left(failure) => println(failure)
case Right(list) => println(list)
}
}
仍然必须确保每个继承特定特征的案例 class 与继承相同特征的其他案例具有不同数量的字段,或者至少与其他案例不同 classes 在这些字段的命名中。
否则,解码器将无法正确完成其工作并将 json 解码为在解码器函数中匹配它的第一种情况 class,而不是正确的预期情况。
第一次尝试:
到目前为止我已经尝试过喷雾-json。我有:
trait Base
case class A ( id: String) extends Base
case class B (id: String) extends Base
现在,为了序列化和反序列化我的 Base
类型,我有代码:
implicit object BaseFormat extends RootJsonFormat[Base]{
def write(obj: Base): JsValue = {
obj match {
case a: A => a.toJson
case b: B => b.toJson
case unknown @ _ => serializationError(s"Marshalling issue with ${unknown}")
}
}
def read(json: JsValue): Base = {
//how to know whether json is encoding an A or a B?
}
}
问题是,为了实现反序列化的 read
方法,我想不出一种方法来知道 JsValue 编码的是 A
还是 B
.
第二次尝试:
为了在 spray-json
中解决这个问题,我最终只是将 A
中的字段 id
重命名为 aID
,并将 B
中的字段重命名为 bID
.
第三次尝试:
由于 spray-json
不如 zio-json
或 circe
等替代库复杂,它们无需额外代码即可自行处理此问题,因此我开始使用 zio-json
现在我得到了错误
magnolia: could not infer DeriveJsonEncoder.Typeclass for type
对于所有情况 类 采用类型参数。 此外,它在链式特征继承方面存在问题。似乎 circe 也使用木兰。所以这很可能也会被 circe 复制。
如有任何帮助,我们将不胜感激。
您应该使用 json encoding/decoding 库解决这个问题。 这是一个使用 circe 的例子,它是半自动模式。
既然你在评论中提到你在你的案例中遇到泛型类型问题 classes,我也把它包括在内。基本上,要为包含 T
的 class Foo[T]
导出编码器或解码器,您必须证明存在编码和解码 T
的方法。这是通过请求一个隐式的 Encoder[T]
和 Decoder[T]
来完成的,您可以在其中导出 Encoder[Foo[T]]
和 Decoder[Foo[T]]
。当然,您可以将此推理概括为适用于多个泛型类型,您只需要隐含地使用一对 encoder/decoder,在其中为相应的情况 class 派生 encoder/decoder。
import io.circe._, io.circe.generic.semiauto._, io.circe.syntax._
case class Foo[T](a: Int, b: String, t: T)
object Foo {
implicit def decoder[T: Encoder: Decoder]: Decoder[Foo[T]] = deriveDecoder
implicit def encoder[T: Encoder: Decoder]: Encoder[Foo[T]] = deriveEncoder
}
case class Bar(a: Int)
object Bar {
implicit val encoder: Encoder[Bar] = deriveEncoder
implicit val decoder: Decoder[Bar] = deriveDecoder
}
case class Baz(a: Int)
println(Foo(42, "hello", 23.4).asJson) // Works because circe knows Encoder[Float]
println(Foo(42, "hello", Bar(42)).asJson) // Works because we defined Encoder[Bar]
//println(Foo(42, "hello", Baz(42)).asJson) // Doesn't compile: circe doesn't know Encoder[Baz] in semi-auto mode
请注意,需要为您使用的每种类型 T
生成 Foo[T]
的不同 encoder/decoder,这就是 [=21= 的编码器和解码器派生的原因] 必须是方法,而不是像 Bar
.
还有一个全自动模式,但它往往会产生编译时错误,对于初学者来说更难调试,所以我会从半自动开始。另一个问题是,自动模式在大型项目上编译可能需要更长的时间。如果你喜欢冒险,不犯错就更美了!
import io.circe._, io.circe.generic.auto._, io.circe.syntax._
case class Foo[T](a: Int, b: String, t: T)
case class Bar(a: Int)
case class Baz(a: Int)
println(Foo(42, "hello", 23.4).asJson) // circe knows Encoder[Float] and automatically derives Encoder[Foo[Float]]
println(Foo(42, "hello", Bar(42)).asJson) // circe wants Encoder[Foo[Bar]], so it ma(cro)gically derives Encoder[Bar] and then Encoder[Foo[Bar]]
println(Foo(42, "hello", Baz(42)).asJson) // Does compile this time, circe automatically find the encoder/decoder for Baz the same way it does for Bar
一个有效的 example 将 traits 与泛型结合使用是这样的:
import io.circe.Decoder.Result
import io.circe._
import io.circe.generic.semiauto._
import io.circe.syntax._
trait MyBase[T <: MyBase[T]] {
def myid: String
def issue: MyBaseIssue
def summary: MyBaseSummary[T]
}
trait MyBaseIssue
object MyBaseIssue {
implicit val decodeIssue: Decoder[MyBaseIssue] =
Decoder[SimpleBaseIssue].map[MyBaseIssue](identity).or(
Decoder[SophisticatedBaseIssue].map[MyBaseIssue](identity)
)
implicit val encodeIssue: Encoder[MyBaseIssue] = Encoder.instance {
case simple @ SimpleBaseIssue(_) => simple.asJson
case sophisticated @ SophisticatedBaseIssue(_) => sophisticated.asJson
}
}
trait MyBaseSummary[T <: MyBase[T]]
object MyBaseSummary {
implicit def decodeSummary[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseSummary[T]] =
Decoder[SimpleBaseSummary].map[MyBaseSummary[SimpleBase]](identity).asInstanceOf[Decoder[MyBaseSummary[T]]].or(
Decoder[SophisticatedBaseSummary].map[MyBaseSummary[SophisticatedBase]](identity).asInstanceOf[Decoder[MyBaseSummary[T]]]
)
implicit def encodeSummary[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseSummary[T]] = Encoder.instance {
case simple @ SimpleBaseSummary(_) => simple.asJson
case sophisticated @ SophisticatedBaseSummary(_) => sophisticated.asJson
}
}
case class SimpleBase(
myid: String,
override val issue: SimpleBaseIssue,
override val summary: SimpleBaseSummary
) extends MyBase[SimpleBase]
case class SophisticatedBase(
myid: String,
extraField: String,
override val issue: SophisticatedBaseIssue,
override val summary: SophisticatedBaseSummary
) extends MyBase[SophisticatedBase]
object SimpleBase {
implicit val encoder: Encoder[SimpleBase] = deriveEncoder
implicit val decoder: Decoder[SimpleBase] = deriveDecoder
}
object SophisticatedBase {
implicit val encoder: Encoder[SophisticatedBase] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBase] = deriveDecoder
}
case class SimpleBaseIssue(simpleIssueType: String) extends MyBaseIssue
case class SophisticatedBaseIssue(sophisticatedIssueType: String) extends MyBaseIssue
object SimpleBaseIssue {
implicit val encoder: Encoder[SimpleBaseIssue] = deriveEncoder
implicit val decoder: Decoder[SimpleBaseIssue] = deriveDecoder
}
object SophisticatedBaseIssue {
implicit val encoder: Encoder[SophisticatedBaseIssue] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBaseIssue] = deriveDecoder
}
case class SimpleBaseSummary(simpleSummary: String) extends MyBaseSummary[SimpleBase]
case class SophisticatedBaseSummary(sophisticatedSummary: String) extends MyBaseSummary[SophisticatedBase]
object SimpleBaseSummary {
implicit val encoder: Encoder[SimpleBaseSummary] = deriveEncoder
implicit val decoder: Decoder[SimpleBaseSummary] = deriveDecoder
}
object SophisticatedBaseSummary {
implicit val encoder: Encoder[SophisticatedBaseSummary] = deriveEncoder
implicit val decoder: Decoder[SophisticatedBaseSummary] = deriveDecoder
}
case class MyBaseList[T <: MyBase[T]](
myid: String,
var membersMap: Map[String, T] = Map.empty,
override val issue: MyBaseListIssues[T],
override val summary: MyBaseListSummary[T]
) extends MyBase[MyBaseList[T]]
object MyBaseList {
implicit def membersMapDecoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[Map[String, T]] = Decoder.decodeMap
implicit def membersMapEncoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[Map[String, T]] = Encoder.encodeMap
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseList[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseList[T]] = deriveDecoder
}
case class MyBaseListIssues[T <: MyBase[T]](
issue: String,
var set: Set[MyBaseIssue] = Set[MyBaseIssue]()
) extends MyBaseIssue
object MyBaseListIssues {
implicit def membersMapDecoder: Decoder[Set[MyBaseIssue]] =
Decoder.decodeSet[MyBaseIssue]
implicit def membersMapEncoder: Encoder[Set[MyBaseIssue]] = Encoder.encodeSet
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseListIssues[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseListIssues[T]] = deriveDecoder
}
case class MyBaseListSummary[T <: MyBase[T]](
summaryList: Map[String, MyBaseSummary[T]]
) extends MyBaseSummary[MyBaseList[T]]
object MyBaseListSummary {
implicit def membersMapDecoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[Map[String, MyBaseSummary[T]]] = Decoder.decodeMap
implicit def membersMapEncoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[Map[String, MyBaseSummary[T]]] = Encoder.encodeMap
implicit def encoder[T <: MyBase[T]: Encoder: Decoder]
: Encoder[MyBaseListSummary[T]] = deriveEncoder
implicit def decoder[T <: MyBase[T]: Encoder: Decoder]
: Decoder[MyBaseListSummary[T]] = deriveDecoder
}
object MainObject extends App {
val simpleList = MyBaseList[SimpleBase]("simpleId",
Map("one" -> SimpleBase("baseid", SimpleBaseIssue("the mistake"), SimpleBaseSummary("very concise"))),
MyBaseListIssues[SimpleBase]("listIssue", Set(SimpleBaseIssue("a disaster"))),
MyBaseListSummary[SimpleBase]( Map("simplebaseid" -> SimpleBaseSummary("super concise")))
)
val simpleJson = simpleList.asJson
println(simpleJson)
val convertedSimpleList = simpleJson.as[MyBaseList[SimpleBase]]
println(convertedSimpleList)
val sphisticatedList = MyBaseList[SophisticatedBase]("sophisticatedId",
Map("one" -> SophisticatedBase("baseid", "further detail", SophisticatedBaseIssue("the mistake"), SophisticatedBaseSummary("very concise"))),
MyBaseListIssues[SophisticatedBase]("listIssue", Set(SophisticatedBaseIssue("a disaster"))),
MyBaseListSummary[SophisticatedBase]( Map("sophisticatedbaseid" -> SophisticatedBaseSummary("super concise")))
)
val sophisticatedJson = sphisticatedList.asJson
println(sophisticatedJson)
val convertedSophisticatedListDecoder: Result[MyBaseList[SophisticatedBase]] = sophisticatedJson.as[MyBaseList[SophisticatedBase]]
println(convertedSophisticatedListDecoder)
convertedSophisticatedListDecoder match {
case Left(failure) => println(failure)
case Right(list) => println(list)
}
}
仍然必须确保每个继承特定特征的案例 class 与继承相同特征的其他案例具有不同数量的字段,或者至少与其他案例不同 classes 在这些字段的命名中。
否则,解码器将无法正确完成其工作并将 json 解码为在解码器函数中匹配它的第一种情况 class,而不是正确的预期情况。