第一次尝试:
到目前为止我已经试过喷雾器了。我有:
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
对于所有接受类型参数的case类。同时,它也存在连锁性状遗传的问题。看来circe也用了木兰。所以这很可能也会在circe身上被复制。
任何帮助都将不胜感激。
发布于 2021-07-02 12:59:13
您应该使用json编码/解码库来解决这个问题。这是一个使用circe的例子,它是半自动模式.
由于您在注释中提到您正在与案例类中的泛型进行斗争,所以我也包括这一点。基本上,要导出包含Foo[T]的类T的编码器或解码器,必须证明有一种方法可以对T进行编码和解码。这是通过请求一个隐式Encoder[T]和Decoder[T]来实现的,您可以在其中派生Encoder[Foo[T]]和Decoder[Foo[T]]。您可以将此推理概括为使用多个泛型类型--当然,您只需在导出相应案例类的编码器/解码器时,就可以隐式地提供一个编码器/解码器对。
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请注意,需要为您正在使用的每种类型的Foo[T]生成不同的编码器/解码器,这就是为什么Foo的编码器和解码器派生必须是方法,而不是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发布于 2021-07-09 06:45:46
使用带有泛型的特性的工作示例如下:
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)
}
}仍然必须确保继承特定特征的每个案例类都有与其他继承相同特征的字段数目不同的字段,或者至少在命名这些字段时与其他案例类不同。
否则,解码器将无法正确地完成其工作,并将json解码为第一个与其在解码器功能中匹配的案例类,而不是正确的预期类。
https://stackoverflow.com/questions/68119808
复制相似问题