首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何在Scala中序列化和反序列化Json的特性?

如何在Scala中序列化和反序列化Json的特性?
EN

Stack Overflow用户
提问于 2021-06-24 16:50:12
回答 2查看 821关注 0票数 1

第一次尝试:

到目前为止我已经试过喷雾器了。我有:

代码语言:javascript
复制
trait Base

case class A ( id: String) extends Base

case class B (id: String) extends Base

现在,为了序列化和反序列化我的Base类型,我有以下代码:

代码语言:javascript
复制
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-jsoncirce )那么复杂,它们自己处理这个问题而不需要额外的代码,所以我开始使用zio-json

现在我知道错误了

magnolia: could not infer DeriveJsonEncoder.Typeclass for type

对于所有接受类型参数的case类。同时,它也存在连锁性状遗传的问题。看来circe也用了木兰。所以这很可能也会在circe身上被复制。

任何帮助都将不胜感激。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2021-07-02 12:59:13

您应该使用json编码/解码库来解决这个问题。这是一个使用circe的例子,它是半自动模式.

由于您在注释中提到您正在与案例类中的泛型进行斗争,所以我也包括这一点。基本上,要导出包含Foo[T]的类T的编码器或解码器,必须证明有一种方法可以对T进行编码和解码。这是通过请求一个隐式Encoder[T]Decoder[T]来实现的,您可以在其中派生Encoder[Foo[T]]Decoder[Foo[T]]。您可以将此推理概括为使用多个泛型类型--当然,您只需在导出相应案例类的编码器/解码器时,就可以隐式地提供一个编码器/解码器对。

代码语言:javascript
复制
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

在Scastie上试试看

请注意,需要为您正在使用的每种类型的Foo[T]生成不同的编码器/解码器,这就是为什么Foo的编码器和解码器派生必须是方法,而不是Bar的值。

也有一个全自动模式,但它往往会产生编译时错误,对初学者来说很难调试,所以我会从半自动开始。另一个问题是,在大型项目上编译自动模式可能需要更长的时间。如果你有冒险精神,当你不犯错误的时候,它会更美!

代码语言:javascript
复制
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

在Scastie上试试看

票数 1
EN

Stack Overflow用户

发布于 2021-07-09 06:45:46

使用带有泛型的特性的工作示例如下:

代码语言:javascript
复制
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解码为第一个与其在解码器功能中匹配的案例类,而不是正确的预期类。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/68119808

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档