套 Circe 编码/解码密封标本 arity 0?

我使用密封的特征 enums 与样品详尽的比较。 在我有对象的情况下 case 而不是课程 case, 扩大我的特质,我想编码和解码 /穿过
http://circe.io
/ 作为一个简单的字符串。

例如:


sealed trait State
case object On extends State
case object Off extends State

val a: State = State.Off
a.asJson.noSpaces // trying for "Off"

decode[State]/"On"/ // should be State.On


我明白它将被调整 0.5.0, 但有人可以帮助我写一些帮助我直到释放的东西?
已邀请:

冰洋

赞同来自:

分配问题 - 假设它是 ADT:


sealed trait State
case object On extends State
case object Off extends State


电流的一般结论 /目前/ 产生以下编码:


scala> import io.circe.generic.auto._, io.circe.syntax._
import io.circe.generic.auto._
import io.circe.syntax._

scala> On.asJson.noSpaces
res0: String = {}

scala> /On: State/.asJson.noSpaces
res1: String = {"On":{}}


这是因为 , 整个派生机制建立在 Shapeless
LabelledGeneric

, 代表对象 case 有多空
HList

s. 它可能总是是默认行为,因为它是干净的,简单且保持一致,但它并不总是你想要的 /如你所知,
https://meta.plasm.us/posts/20 ... tion/
, 这将很快出现,将支持替代方案/.

您可以通过为对象提供自己的通用实例来覆盖此行为。 case:


import io.circe.Encoder
import shapeless.{ Generic, HNil }

implicit def encodeCaseObject[A <: Product]/implicit
gen: Generic.Aux[A, HNil]
/: Encoder[A] = Encoder[String].contramap[A]/_.productPrefix/


它说: "如果是一般的观点
A

它是空的
HList

, 代码用字符串的形式作为您的名称 JSON". 它适用于我们期望对象 case, 静态地键入自己:


scala> On.asJson.noSpaces
res2: String = "On"


当值静态键入为基本类型时,故事略有不同:


scala> /On: State/.asJson.noSpaces
res3: String = {"On":"On"}


我们得到了一个概括的不同副本
State

, 他尊重我们手动定义的对象的通用实例 case, 但仍将它们转变为对象。 如果你想到它 - ADT,它有一些意义

能够

保持课程 case, 这可以合理地仅作为一个物体呈现 JSON, 因此接近 object-wrapper-with-constructor-name-key, 也许是最合理的。

但是,这不是我们唯一可以做的事情

真的

我们静态地知道吗? ADT 班级 case 或只对象 case. 首先,我们需要一个新的类类,这表明了这一点 ADT 仅包括对象 case /请注意,我猜这是一个新的开始,但它应该能够与一般的结论一起完成这项工作。/:


import shapeless._
import shapeless.labelled.{ FieldType, field }

trait IsEnum[C <: Coproduct] {
def to/c: C/: String
def from/s: String/: Option[C]
}

object IsEnum {
implicit val cnilIsEnum: IsEnum[CNil] = new IsEnum[CNil] {
def to/c: CNil/: String = sys.error/"Impossible"/
def from/s: String/: Option[CNil] = None
}

implicit def cconsIsEnum[K <: Symbol, H <: Product, T <: Coproduct]/implicit
witK: Witness.Aux[K],
witH: Witness.Aux[H],
gen: Generic.Aux[H, HNil],
tie: IsEnum[T]
/: IsEnum[FieldType[K, H] :+: T] = new IsEnum[FieldType[K, H] :+: T] {
def to/c: FieldType[K, H] :+: T/: String = c match {
case Inl/h/ => witK.value.name
case Inr/t/ => tie.to/t/
}
def from/s: String/: Option[FieldType[K, H] :+: T] =
if /s == witK.value.name/ Some/Inl/field[K]/witH.value///
else tie.from/s/.map/Inr/_//
}
}


然后是我们的常见副本
Encoder

:


import io.circe.Encoder

implicit def encodeEnum[A, C <: Coproduct]/implicit
gen: LabelledGeneric.Aux[A, C],
rie: IsEnum[C]
/: Encoder[A] = Encoder[String].contramap[A]/a => rie.to/gen.to/a///


具有相同的成功,可以编写解码器。


import cats.data.Xor, io.circe.Decoder

implicit def decodeEnum[A, C <: Coproduct]/implicit
gen: LabelledGeneric.Aux[A, C],
rie: IsEnum[C]
/: Decoder[A] = Decoder[String].emap { s =>
Xor.fromOption/rie.from/s/.map/gen.from/, "enum"/
}


接着:


scala> import io.circe.jawn.decode
import io.circe.jawn.decode

scala> import io.circe.syntax._
import io.circe.syntax._

scala> /On: State/.asJson.noSpaces
res0: String = "On"

scala> /Off: State/.asJson.noSpaces
res1: String = "Off"

scala> decode[State]/""""On""""/
res2: cats.data.Xor[io.circe.Error,State] = Right/On/

scala> decode[State]/""""Off""""/
res3: cats.data.Xor[io.circe.Error,State] = Right/Off/


这就是我们想要的。

要回复问题请先登录注册