- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我是 Scala 新手,正在使用 circe 来建模和序列化一些 API 响应。我发现自己使用以下样板
sealed trait SomeTrait
object SomeTrait {
implicit val someEncoder: Encoder[SomeTrait] = deriveEncoder[SomeTrait]
implicit val someDecoder: Decoder[SomeTrait] = deriveDecoder[SomeTrait]
<code>
}
相反,我想使用泛型,并定义类似的东西
trait SerializableTrait[A] {
implicit val someEncoder: Encoder[A] = deriveEncoder[A]
implicit val someDecoder: Decoder[A] = deriveDecoder[A]
}
然后多次使用扩展:
sealed trait SomeTrait
object SomeTrait extends SerializableTrait[SomeTrain] {
<code>
}
但是我得到无法找到 io.circe.generic.encoding.DerivedAsObjectEncoder 类型的 Lazy 隐式值
,解码器也类似。
我知道我可能正在尝试实现circle.auto
功能,但我想了解这种用法有什么问题。理想情况下,我希望编译器仅在实际需要时在非类型参数化特征内评估 dervieEncoder/Decoder。
最佳答案
您的问题类似于Implicit Json Formatter for value classes in Scala 。就在那里 json 库是 play-json 并且您正在使用 Circe。
deriveEncoder
和deriveDecoder
是macros (实际上不是它们自己,而是它们调用宏)。所以你不能在你想要的地方调用他们。 deriveEncoder[A]
和deriveDecoder[A]
正在尝试扩展A
不是案例类或密封特征(具有案例类子级),而是抽象类型(类型参数)。
将一些公共(public)代码提取到特征并扩展该特征是避免代码重复的 OOP 方法,但宏是一种不同的范例,即元编程。使用元编程,您不能总是遵循 OOP 原则。
deriveEncoder[A]
中和deriveDecoder[A]
现在被称为(扩展)摘要 A
但对于隐式宏,稍后当请求隐式宏时,即当 A
时,它们将被调用(扩展)。被推断为具体的密封特征或案例类。// in a different subproject
import io.circe.{Decoder, Encoder}
import scala.language.experimental.macros
import scala.reflect.macros.whitebox // libraryDependencies += scalaOrganization.value % "scala-reflect" % scalaVersion.value
trait SerializableTrait[A] {
implicit def someEncoder: Encoder[A] = macro SerializableTraitMacros.someEncoderImpl[A]
implicit def someDecoder: Decoder[A] = macro SerializableTraitMacros.someDecoderImpl[A]
}
class SerializableTraitMacros(val c: whitebox.Context) {
import c.universe._
val semiauto = q"_root_.io.circe.generic.semiauto"
def someEncoderImpl[A: WeakTypeTag]: Tree = q"$semiauto.deriveEncoder[${weakTypeOf[A]}]"
def someDecoderImpl[A: WeakTypeTag]: Tree = q"$semiauto.deriveDecoder[${weakTypeOf[A]}]"
}
现在您不需要在案例类或密封特征的伴生对象中定义隐式。你只需要让伴随对象扩展 SerializableTrait
如你所愿
import io.circe.{Decoder, Encoder}
sealed trait SomeTrait
object SomeTrait extends SerializableTrait[SomeTrait]
case class A(i: Int, s: String) extends SomeTrait // the sealed trait must have at least one case-class child
implicitly[Encoder[SomeTrait]] // compiles
implicitly[Decoder[SomeTrait]] // compiles
与 scalacOptions += "-Ymacro-debug-lite"
(也许 "-Xlog-implicits"
也很有用)您可以看到 Circe 实际上为该特征生成了哪些编解码器实例
//scalac: {
// val inst$macro$14: io.circe.generic.encoding.DerivedAsObjectEncoder[App.SomeTrait] = {
// final class anon$someEncoder$macro$13 extends _root_.scala.Serializable {
// def <init>() = {
// super.<init>();
// ()
// };
// lazy val inst$macro$1: io.circe.generic.encoding.DerivedAsObjectEncoder[App.SomeTrait] = encoding.this.DerivedAsObjectEncoder.deriveEncoder[App.SomeTrait, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](shapeless.this.LabelledGeneric.materializeCoproduct[App.SomeTrait, (Symbol @@ String("A")) :: shapeless.HNil, App.A :+: shapeless.CNil, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](DefaultSymbolicLabelling.instance[App.SomeTrait, (Symbol @@ String("A")) :: shapeless.HNil](::.apply[Symbol @@ String("A"), shapeless.HNil.type](scala.Symbol.apply("A").asInstanceOf[Symbol @@ String("A")], HNil)), Generic.instance[App.SomeTrait, App.A :+: shapeless.CNil](((p: App.SomeTrait) => Coproduct.unsafeMkCoproduct((p: p: @_root_.scala.unchecked) match {
// case (_: App.A) => 0
//}, p).asInstanceOf[App.A :+: shapeless.CNil]), ((x$1: App.A :+: shapeless.CNil) => Coproduct.unsafeGet(x$1).asInstanceOf[App.SomeTrait])), coproduct.this.ZipWithKeys.cpZipWithKeys[Symbol @@ String("A"), App.A, shapeless.HNil, shapeless.CNil](coproduct.this.ZipWithKeys.cnilZipWithKeys, Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("A")]](scala.Symbol.apply("A").asInstanceOf[Symbol @@ String("A")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("A")]])), scala.this.<:<.refl[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]), shapeless.Lazy.apply[io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]](inst$macro$2)).asInstanceOf[io.circe.generic.encoding.DerivedAsObjectEncoder[App.SomeTrait]];
// lazy val inst$macro$2: io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] = ({
// final class $anon extends io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] {
// def <init>() = {
// super.<init>();
// ()
// };
// private[this] val circeGenericEncoderForA = shapeless.Lazy.apply[io.circe.generic.encoding.DerivedAsObjectEncoder[App.A]](inst$macro$3).value;
// final def encodeObject(a: shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out): io.circe.JsonObject = shapeless.Inr.apply[Nothing, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](a) match {
// case shapeless.Inr((circeGenericInrBindingForA @ _)) => circeGenericInrBindingForA match {
// case shapeless.Inl((circeGenericInlBindingForA @ _)) => io.circe.JsonObject.singleton("A", $anon.this.circeGenericEncoderForA.apply(circeGenericInlBindingForA))
// case shapeless.Inr(_) => scala.sys.`package`.error("Cannot encode CNil")
// }
// }
// };
// new $anon()
//}: io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]).asInstanceOf[io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]];
// lazy val inst$macro$3: io.circe.generic.encoding.DerivedAsObjectEncoder[App.A] = encoding.this.DerivedAsObjectEncoder.deriveEncoder[App.A, shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](shapeless.this.LabelledGeneric.materializeProduct[App.A, (Symbol @@ String("i")) :: (Symbol @@ String("s")) :: shapeless.HNil, Int :: String :: shapeless.HNil, shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](DefaultSymbolicLabelling.instance[App.A, (Symbol @@ String("i")) :: (Symbol @@ String("s")) :: shapeless.HNil](::.apply[Symbol @@ String("i"), (Symbol @@ String("s")) :: shapeless.HNil.type](scala.Symbol.apply("i").asInstanceOf[Symbol @@ String("i")], ::.apply[Symbol @@ String("s"), shapeless.HNil.type](scala.Symbol.apply("s").asInstanceOf[Symbol @@ String("s")], HNil))), Generic.instance[App.A, Int :: String :: shapeless.HNil](((x0$3: App.A) => x0$3 match {
// case App.this.A((i$macro$10 @ _), (s$macro$11 @ _)) => ::.apply[Int, String :: shapeless.HNil.type](i$macro$10, ::.apply[String, shapeless.HNil.type](s$macro$11, HNil)).asInstanceOf[Int :: String :: shapeless.HNil]
//}), ((x0$4: Int :: String :: shapeless.HNil) => x0$4 match {
// case ::((i$macro$8 @ _), ::((s$macro$9 @ _), HNil)) => App.this.A.apply(i$macro$8, s$macro$9)
//})), hlist.this.ZipWithKeys.hconsZipWithKeys[Symbol @@ String("i"), Int, (Symbol @@ String("s")) :: shapeless.HNil, String :: shapeless.HNil, shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](hlist.this.ZipWithKeys.hconsZipWithKeys[Symbol @@ String("s"), String, shapeless.HNil, shapeless.HNil, shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](hlist.this.ZipWithKeys.hnilZipWithKeys, Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("s")]](scala.Symbol.apply("s").asInstanceOf[Symbol @@ String("s")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("s")]])), Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("i")]](scala.Symbol.apply("i").asInstanceOf[Symbol @@ String("i")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("i")]])), scala.this.<:<.refl[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]), shapeless.Lazy.apply[io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]](inst$macro$12)).asInstanceOf[io.circe.generic.encoding.DerivedAsObjectEncoder[App.A]];
// lazy val inst$macro$12: io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] = ({
// final class $anon extends io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] {
// def <init>() = {
// super.<init>();
// ()
// };
// private[this] val circeGenericEncoderFori = circe.this.Encoder.encodeInt;
// private[this] val circeGenericEncoderFors = circe.this.Encoder.encodeString;
// final def encodeObject(a: shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out): io.circe.JsonObject = a match {
// case shapeless.::((circeGenericHListBindingFori @ _), shapeless.::((circeGenericHListBindingFors @ _), shapeless.HNil)) => io.circe.JsonObject.fromIterable(scala.collection.immutable.Vector.apply[(String, io.circe.Json)](scala.Tuple2.apply[String, io.circe.Json]("i", $anon.this.circeGenericEncoderFori.apply(circeGenericHListBindingFori)), scala.Tuple2.apply[String, io.circe.Json]("s", $anon.this.circeGenericEncoderFors.apply(circeGenericHListBindingFors))))
// }
// };
// new $anon()
//}: io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]).asInstanceOf[io.circe.generic.encoding.ReprAsObjectEncoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]]
// };
// new anon$someEncoder$macro$13().inst$macro$1
// };
// _root_.shapeless.Lazy.apply[io.circe.generic.encoding.DerivedAsObjectEncoder[App.SomeTrait]](inst$macro$14)
//}
//scalac: {
// val inst$macro$14: io.circe.generic.decoding.DerivedDecoder[App.SomeTrait] = {
// final class anon$someDecoder$macro$13 extends _root_.scala.Serializable {
// def <init>() = {
// super.<init>();
// ()
// };
// lazy val inst$macro$1: io.circe.generic.decoding.DerivedDecoder[App.SomeTrait] = decoding.this.DerivedDecoder.deriveDecoder[App.SomeTrait, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](shapeless.this.LabelledGeneric.materializeCoproduct[App.SomeTrait, (Symbol @@ String("A")) :: shapeless.HNil, App.A :+: shapeless.CNil, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](DefaultSymbolicLabelling.instance[App.SomeTrait, (Symbol @@ String("A")) :: shapeless.HNil](::.apply[Symbol @@ String("A"), shapeless.HNil.type](scala.Symbol.apply("A").asInstanceOf[Symbol @@ String("A")], HNil)), Generic.instance[App.SomeTrait, App.A :+: shapeless.CNil](((p: App.SomeTrait) => Coproduct.unsafeMkCoproduct((p: p: @_root_.scala.unchecked) match {
// case (_: App.A) => 0
//}, p).asInstanceOf[App.A :+: shapeless.CNil]), ((x$1: App.A :+: shapeless.CNil) => Coproduct.unsafeGet(x$1).asInstanceOf[App.SomeTrait])), coproduct.this.ZipWithKeys.cpZipWithKeys[Symbol @@ String("A"), App.A, shapeless.HNil, shapeless.CNil](coproduct.this.ZipWithKeys.cnilZipWithKeys, Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("A")]](scala.Symbol.apply("A").asInstanceOf[Symbol @@ String("A")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("A")]])), scala.this.<:<.refl[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]), shapeless.Lazy.apply[io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]](inst$macro$2)).asInstanceOf[io.circe.generic.decoding.DerivedDecoder[App.SomeTrait]];
// lazy val inst$macro$2: io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] = ({
// final class $anon extends io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] {
// def <init>() = {
// super.<init>();
// ()
// };
// private[this] val circeGenericDecoderForA = shapeless.Lazy.apply[io.circe.generic.decoding.DerivedDecoder[App.A]](inst$macro$3).value;
// final def apply(c: io.circe.HCursor): io.circe.Decoder.Result[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] = {
// val result = c.downField("A");
// if (result.succeeded)
// scala.Some.apply[io.circe.Decoder.Result[App.A]]($anon.this.circeGenericDecoderForA.tryDecode(result))
// else
// scala.None
// } match {
// case scala.Some((result @ _)) => result match {
// case scala.util.Right((v @ _)) => scala.util.Right.apply[Nothing, shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](ReprDecoder.injectLeftValue[Symbol @@ String("A"), App.A, shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](v))
// case scala.util.Left((err @ _)) => scala.util.Left.apply[io.circe.DecodingFailure, Nothing](err)
// }
// case scala.None => (scala.util.Left.apply[io.circe.DecodingFailure, shapeless.CNil](io.circe.DecodingFailure.apply("JSON decoding to CNil should never happen", c.history)): scala.util.Either[io.circe.DecodingFailure, shapeless.CNil]) match {
// case scala.util.Right((v @ _)) => scala.util.Right.apply[Nothing, shapeless.Inr[Nothing,shapeless.CNil]](shapeless.Inr.apply[Nothing, shapeless.CNil](v))
// case scala.util.Left((err @ _)) => scala.util.Left.apply[io.circe.DecodingFailure, Nothing](err)
// }
// };
// final override def decodeAccumulating(c: io.circe.HCursor): io.circe.Decoder.AccumulatingResult[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out] = {
// val result = c.downField("A");
// if (result.succeeded)
// scala.Some.apply[io.circe.Decoder.AccumulatingResult[App.A]]($anon.this.circeGenericDecoderForA.tryDecodeAccumulating(result))
// else
// scala.None
// } match {
// case scala.Some((result @ _)) => result.map[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](((v: App.A) => ReprDecoder.injectLeftValue[Symbol @@ String("A"), App.A, shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out](v)))
// case scala.None => cats.data.Validated.invalidNel[io.circe.DecodingFailure, shapeless.CNil](io.circe.DecodingFailure.apply("JSON decoding to CNil should never happen", c.history)).map[shapeless.Inr[Nothing,shapeless.CNil]](((x$3: shapeless.CNil) => shapeless.Inr.apply[Nothing, shapeless.CNil](x$3)))
// }
// };
// new $anon()
//}: io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]).asInstanceOf[io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("A"),App.A] :+: shapeless.ops.coproduct.ZipWithKeys.cnilZipWithKeys.Out]];
// lazy val inst$macro$3: io.circe.generic.decoding.DerivedDecoder[App.A] = decoding.this.DerivedDecoder.deriveDecoder[App.A, shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](shapeless.this.LabelledGeneric.materializeProduct[App.A, (Symbol @@ String("i")) :: (Symbol @@ String("s")) :: shapeless.HNil, Int :: String :: shapeless.HNil, shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](DefaultSymbolicLabelling.instance[App.A, (Symbol @@ String("i")) :: (Symbol @@ String("s")) :: shapeless.HNil](::.apply[Symbol @@ String("i"), (Symbol @@ String("s")) :: shapeless.HNil.type](scala.Symbol.apply("i").asInstanceOf[Symbol @@ String("i")], ::.apply[Symbol @@ String("s"), shapeless.HNil.type](scala.Symbol.apply("s").asInstanceOf[Symbol @@ String("s")], HNil))), Generic.instance[App.A, Int :: String :: shapeless.HNil](((x0$3: App.A) => x0$3 match {
// case App.this.A((i$macro$10 @ _), (s$macro$11 @ _)) => ::.apply[Int, String :: shapeless.HNil.type](i$macro$10, ::.apply[String, shapeless.HNil.type](s$macro$11, HNil)).asInstanceOf[Int :: String :: shapeless.HNil]
//}), ((x0$4: Int :: String :: shapeless.HNil) => x0$4 match {
// case ::((i$macro$8 @ _), ::((s$macro$9 @ _), HNil)) => App.this.A.apply(i$macro$8, s$macro$9)
//})), hlist.this.ZipWithKeys.hconsZipWithKeys[Symbol @@ String("i"), Int, (Symbol @@ String("s")) :: shapeless.HNil, String :: shapeless.HNil, shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](hlist.this.ZipWithKeys.hconsZipWithKeys[Symbol @@ String("s"), String, shapeless.HNil, shapeless.HNil, shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out](hlist.this.ZipWithKeys.hnilZipWithKeys, Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("s")]](scala.Symbol.apply("s").asInstanceOf[Symbol @@ String("s")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("s")]])), Witness.mkWitness[Symbol with shapeless.tag.Tagged[String("i")]](scala.Symbol.apply("i").asInstanceOf[Symbol @@ String("i")].asInstanceOf[Symbol with shapeless.tag.Tagged[String("i")]])), scala.this.<:<.refl[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]), shapeless.Lazy.apply[io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]](inst$macro$12)).asInstanceOf[io.circe.generic.decoding.DerivedDecoder[App.A]];
// lazy val inst$macro$12: io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] = ({
// final class $anon extends io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] {
// def <init>() = {
// super.<init>();
// ()
// };
// private[this] val circeGenericDecoderFori = circe.this.Decoder.decodeInt;
// private[this] val circeGenericDecoderFors = circe.this.Decoder.decodeString;
// final def apply(c: io.circe.HCursor): io.circe.Decoder.Result[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] = ReprDecoder.consResults[io.circe.Decoder.Result, Symbol @@ String("i"), Int, shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]($anon.this.circeGenericDecoderFori.tryDecode(c.downField("i")), ReprDecoder.consResults[io.circe.Decoder.Result, Symbol @@ String("s"), String, shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]($anon.this.circeGenericDecoderFors.tryDecode(c.downField("s")), ReprDecoder.hnilResult)(io.circe.Decoder.resultInstance))(io.circe.Decoder.resultInstance);
// final override def decodeAccumulating(c: io.circe.HCursor): io.circe.Decoder.AccumulatingResult[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out] = ReprDecoder.consResults[io.circe.Decoder.AccumulatingResult, Symbol @@ String("i"), Int, shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]($anon.this.circeGenericDecoderFori.tryDecodeAccumulating(c.downField("i")), ReprDecoder.consResults[io.circe.Decoder.AccumulatingResult, Symbol @@ String("s"), String, shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]($anon.this.circeGenericDecoderFors.tryDecodeAccumulating(c.downField("s")), ReprDecoder.hnilResultAccumulating)(io.circe.Decoder.accumulatingResultInstance))(io.circe.Decoder.accumulatingResultInstance)
// };
// new $anon()
//}: io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]).asInstanceOf[io.circe.generic.decoding.ReprDecoder[shapeless.labelled.FieldType[Symbol @@ String("i"),Int] :: shapeless.labelled.FieldType[Symbol @@ String("s"),String] :: shapeless.ops.hlist.ZipWithKeys.hnilZipWithKeys.Out]]
// };
// new anon$someDecoder$macro$13().inst$macro$1
// };
// _root_.shapeless.Lazy.apply[io.circe.generic.decoding.DerivedDecoder[App.SomeTrait]](inst$macro$14)
//}
如果你想要implicitly[Encoder[A]]
, implicitly[Decoder[A]]
要编译,你应该定义companion object A extends SerializableTrait[A]
。所以最好调用SerializableTrait
不同的是,SerializableTraitOrClass
或类似的东西。
import scala.annotation.{StaticAnnotation, compileTimeOnly}
import scala.reflect.macros.blackbox
import scala.language.experimental.macros
@compileTimeOnly("""enable macro annotations: scalacOptions += "-Ymacro-annotations" """)
class serializableTrait extends StaticAnnotation {
def macroTransform(annottees: Any*): Any = macro SerializableTraitMacros.macroTransformImpl
}
object SerializableTraitMacros {
def macroTransformImpl(c: blackbox.Context)(annottees: c.Tree*): c.Tree = {
import c.universe._
val circe = q"_root_.io.circe"
val semiauto = q"$circe.generic.semiauto"
def modifyObject(obj: Tree): Tree = obj match {
case q"$mods object $tname extends { ..$earlydefns } with ..$parents { $self => ..$body }" =>
val className = tname.toTypeName
val encoder = TermName(c.freshName(s"${tname}Encoder"))
val decoder = TermName(c.freshName(s"${tname}Decoder"))
q"""$mods object $tname extends { ..$earlydefns } with ..$parents { $self =>
..$body
implicit val $encoder: $circe.Encoder[$className] = $semiauto.deriveEncoder[$className]
implicit val $decoder: $circe.Decoder[$className] = $semiauto.deriveDecoder[$className]
}"""
}
def modify(cls: Tree, obj: Tree): Tree = q"..${Seq(cls, modifyObject(obj))}"
annottees match {
case (cls: ClassDef) :: (obj: ModuleDef) :: Nil => modify(cls, obj)
case (cls: ClassDef) :: Nil => modify(cls, q"object ${cls.name.toTermName}")
case (obj: ModuleDef) :: Nil => modifyObject(obj) // this works for the companion object of a sealed trait or top-level case class but not nested case class
}
}
}
import io.circe.{Decoder, Encoder}
@serializableTrait
sealed trait SomeTrait
case class A(i: Int, s: String) extends SomeTrait
implicitly[Encoder[SomeTrait]] // compiles
implicitly[Decoder[SomeTrait]] // compiles
//scalac: object SomeTrait extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// implicit val SomeTraitEncoder$macro$1: _root_.io.circe.Encoder[SomeTrait] = _root_.io.circe.generic.semiauto.deriveEncoder[SomeTrait];
// implicit val SomeTraitDecoder$macro$2: _root_.io.circe.Decoder[SomeTrait] = _root_.io.circe.generic.semiauto.deriveDecoder[SomeTrait]
//}
如果你想要implicitly[Encoder[A]]
, implicitly[Decoder[A]]
要编译,您应该注释案例类 A
也是。
宏注释现已实现,以便您可以注释特征或其伴生对象(无论如何,隐式将在伴生对象中生成),但由于某种原因,如果您注释案例的伴生对象,则这不起作用类( could not find Lazy implicit value of type io.circe.generic.encoding.DerivedAsObjectEncoder[A]
)。 这似乎发生是因为我测试了嵌套 SomeTrait
和A
,对于顶级来说没问题。
实际上,我们的宏注释与标准的@JsonCodec
类似。
https://circe.github.io/circe/codecs/semiauto-derivation.html#jsoncodec
import io.circe.generic.JsonCodec
@JsonCodec
sealed trait SomeTrait
@JsonCodec
case class A(i: Int, s: String) extends SomeTrait
// object SomeTrait extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// implicit val codecForSomeTrait: AsObject[SomeTrait] = semiauto.deriveCodec[SomeTrait]
// };
// object A extends scala.AnyRef {
// def <init>() = {
// super.<init>();
// ()
// };
// implicit val codecForA: AsObject[A] = semiauto.deriveCodec[A]
// };
关于scala - Scala 中隐式值方法的类型参数 - Circe,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/74364545/
我正在尝试为菊石 REPL 创建一个 predef.sc 文件。这是我写的 val fs2Version = "2.2.2" val circeVersion = "0.13.0" // fs2 in
我正在尝试为两个案例类生成编码器和解码器: object EventBusCases { case class ValuationRequest(function: RequestValue =
我已经为 JSON 表示定义了几个 case 类,但我不确定我是否做得正确,因为有很多嵌套的 case 类。 spec、meta 等实体属于 JSONObject 类型以及自定义对象本身。 这是我定义
为什么我得到错误 could not find Lazy implicit value of type io.circe.generic.decoding.DerivedDecoder[A$A6.th
我正在尝试将一些类编码为 json 字符串,但是无论我尝试什么,我的类似乎都无法为我正在使用的案例类找到隐式编码器。 这是我能够精简到的最小示例。 import io.circe._ import i
我以前见过类似的问题,但没有一个有效。我认为他们会问一些不同的问题,所以我在这里问。 我在一个文件中有这样的东西: sealed trait Thing case class SomeThing()
我的目标是将 JSON 转换为以下模型: case class Container(typeId: Int, timestamp: Long, content: Content) sealed tra
我想用 Circe 解码以下 ADT: sealed trait PaymentType object PaymentType extends EnumEncoder[PaymentType] {
我想将案例类的 Array[Byte] 字段编码为 Base64 字符串。出于某种原因,Circe 没有使用默认编解码器选择我的编解码器,而是将字节数组转换为 json 整数数组。 我应该怎么做才能修
我正在尝试使用 scala json 库 Circe,将它包装在一个简单的 trait 中以提供与 json 的转换,我有以下内容: import io.circe.generic.auto._ im
我试图将“5m”或“5s”或“5ms”形式的字符串解码为 FiniteDuration 类型的对象,分别为 5.minutes、5.seconds、5.milliseconds。 我正在尝试为涉及 F
当字段可以具有不同的原始值类型时,我在解析 json 时遇到问题。例如,我可以得到 json: { "name" : "john", "age" : 31 } 或者它可以是这种形式: {
我有一些 json,其中包含一些字段,这些字段被压缩为 bson-ish 格式,如 {"foo.bar" : "bash"} .我想将其转换为以下表示 {"foo" : { "bar" : "bash
我正在尝试实现类似的东西 object Claims { import shapeless._ import shapeless.labelled.FieldType import io.
我正在尝试使用 Circe 对对象列表进行编码,看起来类似于: val test = Seq(MyObject("hello", None, 1, 2, None) 我正在尝试使用 Circe 解析它
我的问题有点棘手。我有一个看起来像这样的案例类 case class Foo( id: String, name: String, field1: Boolean, f
我有以下案例类: final case class Camel(firstName: String, lastName: String, waterPerDay: Int) 和circe配置: obj
有没有办法将单个 None 字段序列化为“null”? 例如: // When None, I'd like to serialize only f2 to `null` case class Exa
我是 Scala 新手,正在使用 circe 来建模和序列化一些 API 响应。我发现自己使用以下样板 sealed trait SomeTrait object SomeTrait { im
可以有一个如下所示的类: case class Amount(value: Int) case class Data(insurance: Option[Amount], itemPrice: Amo
我是一名优秀的程序员,十分优秀!