scala 从Circe的asJson输出中删除Case类定义

z2acfund  于 2022-12-13  发布在  Scala
关注(0)|答案(1)|浏览(159)

请考虑:

import io.circe.generic.auto._, io.circe.syntax._
sealed trait Data
case class Failed(foo: String, bar: String) extends Data
case class Success(foo1:String, bar1:String) extends Data
case class Task(Foo:String, Data: Data)

val something = Task("test", Failed("1", "2"))
println(something.asJson)

这将输出:

val something: Task = Task(test,Failed(1,2))
{"Foo" : "test", "Data" : {"Failed" : {"foo" : "1","bar" : "2"}}}

但我真正想要的,是它能够输出:

{"Foo" : "test", "Data" : {"foo" : "1", "bar" : "2"}}

实际上,我只想删除“失败”块,但保留该块中的所有内容。
组建信息:

val scalaVer = "2.13.8"

lazy val circeJsonSchemaVersion = "0.2.0"
lazy val circeVersion = "0.14.3"
lazy val circeOpticsVersion = "0.14.1"

"io.circe" %% "circe-json-schema" % circeJsonSchemaVersion,
"io.circe" %% "circe-core" % circeVersion,
"io.circe" %% "circe-generic" % circeVersion,
"io.circe" %% "circe-parser" % circeVersion,
"io.circe" %% "circe-literal" % circeVersion,
"io.circe" %% "circe-generic-extras" % circeVersion,
"io.circe" %% "circe-optics" % circeOpticsVersion,

我试过使用@JsonCodec,但无法让它工作。我看了自定义的编解码器,但似乎它可能是一个巨大的兔子洞。
编辑:修复了输出中的错误复制/粘贴

erhoui1w

erhoui1w1#

更通用的解决方案建议

import GenericDerivation.{ decodeEvent => _, encodeEvent => _ }

object ShapesDerivation {
  import io.circe.shapes // "io.circe" %% "circe-shapes" % ...
  import shapeless.{ Coproduct, Generic }

  implicit def encodeAdtNoDiscr[A, Repr <: Coproduct](implicit
    gen: Generic.Aux[A, Repr],
    encodeRepr: Encoder[Repr]
  ): Encoder[A] = encodeRepr.contramap(gen.to)

  //...
}

但这似乎已经过时了。
您可以尝试自己手动导出无标签联产品的编码器(即Failed :+: Success :+: CNil形式的联产品,而不是FieldType[Symbol @@ "Failed", Failed] :+: FieldType[Symbol @@ "Success", Success] :+: CNil

import io.circe.Encoder
import shapeless.{:+:, CNil, Coproduct, Generic, Inl, Inr}

trait NoLabelCoproductEncoders {
  implicit def noLabelEnc[A, Repr <: Coproduct](implicit
    gen: Generic.Aux[A, Repr],
    enc: NoLabelCoproductEncoder[Repr]
  ): Encoder[A] = enc.contramap(gen.to)
}

trait NoLabelCoproductEncoder[A <: Coproduct] extends Encoder[A]
object NoLabelCoproductEncoder {
  implicit def ccons[H, T <: Coproduct](implicit
    hEnc: Encoder[H],
    tEnc: NoLabelCoproductEncoder[T]
  ): NoLabelCoproductEncoder[H :+: T] = {
    case Inl(h) => hEnc(h)
    case Inr(t) => tEnc(t)
  }

  implicit val cnil: NoLabelCoproductEncoder[CNil] = _.impossible
}

这适用于semiauto

import io.circe.generic.semiauto

sealed trait Data
object Data extends NoLabelCoproductEncoders

case class Failed(foo: String, bar: String) extends Data
object Failed {
  implicit val failedEnc: Encoder[Failed] = semiauto.deriveEncoder[Failed]
}
case class Success(foo1:String, bar1:String) extends Data
object Success {
  implicit val successEnc: Encoder[Success] = semiauto.deriveEncoder[Success]
}

case class Task(Foo:String, Data: Data)
object Task {
  implicit def taskEnc: Encoder[Task] = semiauto.deriveEncoder
}

import io.circe.syntax._

val something = Task("test", Failed("1", "2"))
something.asJson.noSpaces
// {"Foo":"test","Data":{"foo":"1","bar":"2"}}

和与auto

sealed trait Data
object Data extends NoLabelCoproductEncoders

case class Failed(foo: String, bar: String) extends Data
case class Success(foo1:String, bar1:String) extends Data

case class Task(Foo:String, Data: Data)

import io.circe.generic.auto._
import Data._ // to make noLabelEnc of higher priority for Data, otherwise it's ambiguous with Circe auto._ encoders (in LowPriorityEncoders)
import io.circe.syntax._

val something = Task("test", Failed("1", "2"))
something.asJson.noSpaces
// {"Foo":"test","Data":{"foo":"1","bar":"2"}}

相关问题