Как я могу определить общий декодер / кодировщик с помощью circe?

Предположим, у меня есть несколько типов идентификаторов, определенных следующим образом.

sealed trait Id {
  val value: String
}
case class IdA(value: String) extends Id
case class IdB(value: String) extends Id
case class IdC(value: String) extends Id

Эти классы должны быть декодированы из следующего JSON и закодированы в него.

 {
    "id: "some-id"
 }

Как я могу определить общий декодер / кодировщик для идентификатора,

case class A(id: IdA, name: String, count: Int)
case class B(id: IdB, name: String, count: Int)
case class C(id: IdC, name: String, count: Int)

чтобы вышеперечисленные классы можно было декодировать и закодировать в JSON ниже?

{
   "id" : "some-id",
   "name": "some-name",
   "count": 2
}

если возможно, я хочу, чтобы поле id было гибким как для декодера, так и для кодировщика, то есть id может быть id-x в одном случае и id-y в другом.


person d-_-b    schedule 14.02.2021    source источник
comment
Вы можете создать собственный Codec для признака Id, определяющий, как он должен работать.   -  person Luis Miguel Mejía Suárez    schedule 14.02.2021
comment
Не могли бы вы привести пример реализации?   -  person d-_-b    schedule 15.02.2021
comment
Вы можете ознакомиться с официальной документацией по пользовательским кодекам   -  person francoisr    schedule 15.02.2021
comment
Мне кажется, вы смешиваете несколько вопросов в один. Какой json должен декодировать в какие классы? И какие классы должны кодировать в какие jsons?   -  person Tomer Shetah    schedule 15.02.2021


Ответы (1)


Я решил это, просто определив следующие декодер и кодировщик.

import cats.implicits._
import io.circe.{Decoder, Encoder}
import shapeless._

 implicit def encoderValueClass[T <: Id, V](implicit
      g: Lazy[Generic.Aux[T, V :: HNil]],
      e: Encoder[V]
  ): Encoder[T] = Encoder.instance { value =>
    e(g.value.to(value).head)
  }

  implicit def idDecoder[T <: Id, V](implicit
      g: Lazy[Generic.Aux[T, V :: HNil]],
      d: Decoder[V]
  ): Decoder[T] = Decoder.instance { cursor =>
    d(cursor).map { value =>
      g.value.from(value :: HNil)
    }
  }
person d-_-b    schedule 15.02.2021