Как я могу получить у circe сценарий вывода для сгенерированного Json? - PullRequest
3 голосов
/ 03 мая 2019

Вот что я намереваюсь - скажем, у меня есть поле с именем medical_payments - оно может «либо» быть пределом , если один из них выбрал, либо отказался

{
  "medical_payments": 
    {
      "limit_value":"one_hundred"
    }
} 

Если он выбран в качестве отказа, то должно быть:

{
  "medical_payments": 
    {
      "waived":true
    }
} 

Пока вот что у меня есть:

sealed trait LimitOrWaiver
case class Limit(limit_key: String) extends LimitOrWaiver
case class Waived(waived: Boolean) extends LimitOrWaiver

case class Selection(medical_payments: LimitOrWaiver)

Пример данных:

Selection(medical_payments = Limit("one_hundred")).asJson

Вывод:

{
  "medical_payments": 
    {
      "Limit": { "limit_value":"one_hundred" } // additional object added
    }
} 

Аналогично для Selection(medical_payments = Waived(true)).asJson к Json добавляется Waived:{...}.

Я бы хотел, чтобы это было либо /, либо.Каков наилучший способ добиться этого?

Единственный способ, которым я смог придумать (мне не нравится), - это использовать forProductN функций для документа и вручнуюсделайте все это - но это будет громоздко для большого Json.

1 Ответ

5 голосов
/ 03 мая 2019

Вы можете почти выполнить это с помощью общего деривации, используя конфигурацию в generic-extras:

sealed trait LimitOrWaiver
case class Limit(limitValue: String) extends LimitOrWaiver
case class Waived(waived: Boolean) extends LimitOrWaiver
case class Selection(medicalPayments: LimitOrWaiver)

import io.circe.generic.extras.Configuration, io.circe.generic.extras.auto._
import io.circe.syntax._

implicit val codecConfiguration: Configuration =
  Configuration.default.withDiscriminator("type").withSnakeCaseMemberNames

А потом:

scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
  "medical_payments" : {
    "limit_value" : "one_hundred",
    "type" : "Limit"
  }
}

(Обратите внимание, что я также изменил имена членов класса case в Scala на идиоматический случай верблюда Scala и обрабатываю преобразование в случай змеи в конфигурации.)

Это не совсем то, что вам нужно, поскольку есть этот дополнительный элемент type, но универсальный вывод circe поддерживает только кодирующие / декодирующие устройства с возможностью кругового обхода и без какого-либо дискриминатора - либо член, подобный этому, либо дополнительный объектный слой, который вы указали в вопросе - невозможно выполнить обход значений произвольных ADT через JSON.

Это может быть хорошо - вы можете не заботиться о дополнительных type в вашем объекте. Если вам все равно, вы все равно можете использовать деривацию с небольшой дополнительной работой:

import io.circe.generic.extras.Configuration, io.circe.generic.extras.auto._
import io.circe.generic.extras.semiauto._
import io.circe.ObjectEncoder, io.circe.syntax._

implicit val codecConfiguration: Configuration =
  Configuration.default.withDiscriminator("type").withSnakeCaseMemberNames

implicit val encodeLimitOrWaiver: ObjectEncoder[LimitOrWaiver] =
  deriveEncoder[LimitOrWaiver].mapJsonObject(_.remove("type"))

И

scala> Selection(medicalPayments = Limit("one_hundred")).asJson
res0: io.circe.Json =
{
  "medical_payments" : {
    "limit_value" : "one_hundred"
  }
}

Если вы действительно хотите, вы можете сделать это автоматически, так что type будет удален из любых кодировщиков ADT, которые вы получите.

...