对于case class Apple(color:String, sweetness:Double)
,我可以通过generic。(semi)auto或generic.extras。(semi)auto来定义Decoder[String => Apple]
,
但是对于密封的特征等级(ADT),我不能:
sealed trait Fruit {
def color:String
}
case class Apple(color:String, sweetness:Double) extends Fruit
sealed trait SpecialFruit extends Fruit
case class Camachile(color:String, burstyness:Double) extends SpecialFruit
case class Langsat(color:String, transparency:Double) extends SpecialFruit
Decoder[String => Fruit] // <--- wont compile
如何创建这样的解码器?
更新 我之所以需要这样的解码器,是因为 -我解析的json不包含所有字段。 -为丢失的字段获取解码器并非易事。
最后一点使得无法通过Decoder [Fruit]
答案 0 :(得分:1)
使用decode[Fruit](jsonString)
,下面是示例:
https://scalafiddle.io/sf/jvySm0B/0
在circe的主页上有一个类似的示例:https://circe.github.io/circe/
答案 1 :(得分:0)
这是我尝试的实现。警告:可能与Circe的编码标准有点不同,但是对于我来说,它似乎可以正常工作。还支持嵌套的密封特征。
package no.kodeworks.kvarg.json
import io.circe.generic.extras.Configuration
import io.circe.{Decoder, HCursor}
import no.kodeworks.kvarg.util._
import shapeless.ops.function.FnFromProduct
import shapeless.ops.union.UnzipFields
import shapeless.{Coproduct, HList, LabelledGeneric, _}
trait AdtConfiguredIncompleteDecoders {
implicit def decodeIncompleteAdt[
Missing <: HList
, Adt
, Func
, Subtypes <: Coproduct
, SubtypeKeys <: HList
, SubtypeValues <: Coproduct
, ParamsSubtypes <: HList
, SubtypeFuncs <: HList
]
(implicit
func: FnFromProduct.Aux[Missing => Adt, Func],
sub: LabelledGeneric.Aux[Adt, Subtypes],
uz: UnzipFields.Aux[Subtypes, SubtypeKeys, SubtypeValues],
subtypeFuncs: SubtypeFunc.Aux[Missing, SubtypeValues, SubtypeFuncs],
configuration: Configuration = null
): Decoder[Func] = {
val conf = Option(configuration).getOrElse(Configuration.default)
val disc = conf.discriminator.getOrElse("type")
val keys = hlistToList[Symbol](uz.keys()).map(_.name)
.map(conf.transformConstructorNames)
val subtypeFuncs0 = hlistToList[Decoder[Func]](subtypeFuncs())
Decoder.withReattempt {
case h: HCursor =>
h.downField(disc).as[String] match {
case Right(decodedType) =>
val subtypeFuncDecoder = subtypeFuncs0(keys.indexOf(decodedType))
subtypeFuncDecoder(h)
}
}
}
trait SubtypeFunc[P <: HList, A <: Coproduct] extends DepFn0 with Serializable {
type Out <: HList
}
object SubtypeFunc {
type Aux[P <: HList, A <: Coproduct, Out0 <: HList] = SubtypeFunc[P, A] {
type Out = Out0}
implicit def cnilSubtypeFunc[P <: HList]: Aux[P, CNil, HNil] = new SubtypeFunc[P, CNil] {
type Out = HNil
override def apply(): HNil = HNil
}
implicit def cconsSubtypeFunc[
Missing <: HList
, CaseClass
, Func
, Rest <: Coproduct]
(implicit
func: FnFromProduct.Aux[Missing => CaseClass, Func],
subtypefuncHead: Decoder[Func],
subtypeFuncRest: SubtypeFunc[Missing, Rest],
): SubtypeFunc.Aux[Missing, CaseClass :+: Rest, Decoder[Func] :: subtypeFuncRest.Out] = {
new SubtypeFunc[Missing, CaseClass :+: Rest] {
type Out = Decoder[Func] :: subtypeFuncRest.Out
override def apply() =
subtypefuncHead :: subtypeFuncRest()
}
}
}
}
从no.kodeworks.kvarg.util包对象中摘录:
def hlistToList[T](hlist: shapeless.HList): List[T] = {
import shapeless._
hlist match {
case HNil => Nil
case head :: tail =>
collection.immutable.::(head.asInstanceOf[T], hlistToList[T](tail))
}
}