Как представить динамические ключи JSON в Scala при использовании circe

Я пытаюсь представить следующий JSON как класс случая Scala:

     {
       "cars": {
          "THIS IS A DYNAMIC KEY 1": {
            "name": "bla 1",
          },
          "THIS IS A DYNAMIC KEY 2": {
            "name": "bla 2",
          }
          ...
      }

Тем не менее, мой JSON имеет динамические ключи, которые я не буду знать во время выполнения, и я хотел бы использовать circe для кодирования / декодирования. Я использую правильный способ представить это с помощью Scala?

import io.circe.generic.JsonCodec

@JsonCodec
case class Cars(cars: List[Car])

@JsonCodec
case class Car(whatShouldThisBe: CarDetails) // Not sure how to represent this?

@JsonCodec
case class CarDetails(name: String)

2 ответа

Решение

Я думаю, что вы можете просто использовать Map[String, CarDetails], Ваша ADT становится:

import io.circe.generic.JsonCodec

@JsonCodec
case class Cars(cars: Map[String, CarDetails])

@JsonCodec
case class CarDetails(name: String)

Единственный сложный момент может быть, если вам требуется хотя бы один объект CarDetails или если ноль является приемлемым. Цирцея, кажется, поддерживает cats.data.NonEmptyMap если это потребуется.

Самый простой способ справиться с таким делом, вероятно, это изменить cars член Cars класс case, чтобы иметь тип как Map[String, CarDetails]опуская Car кейс класс в целом. Если вы это сделаете, ваш код будет работать точно так же, как есть (минус Car определение), и декодирует предоставленный вами пример JSON.

Если вы хотите что-то ближе к вашей структуре класса дел, вы можете сделать следующее:

import io.circe.Decoder
import io.circe.generic.JsonCodec

case class Cars(cars: List[Car])

object Cars {
  implicit val decodeCars: Decoder[Cars] =
    Decoder[Map[String, CarDetails]].prepare(_.downField("cars")).map(kvs =>
      Cars(
        kvs.map {
          case (k, v) => Car(k, v)
        }.toList
      )
    )
}

// I've added an `id` member here as a way to hold on to the JSON key.
case class Car(id: String, whatShouldThisBe: CarDetails)

@JsonCodec
case class CarDetails(name: String)

Это будет декодировать тот же JSON, но будет включать динамические ключи в Car уровень.

Другие вопросы по тегам