Вот моя попытка реализации.Предупреждение: это, вероятно, немного не соответствует стандартам кодирования в 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))
}
}