使用 circe 时如何在 Scala 中表示动态 JSON 键

How to represent dynamic JSON keys in Scala when using circe

我试图将以下 JSON 表示为 Scala 案例 class:

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

但是,我的 JSON 有我在运行时不知道的动态键,我想使用 circe 到 encode/decode。我使用 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)

我想你可以使用 Map[String, CarDetails]。您的 ADT 将变为:

import io.circe.generic.JsonCodec

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

@JsonCodec
case class CarDetails(name: String)

唯一棘手的一点可能是您是否需要至少一个 CarDetails 对象,或者是否可以接受零。如果需要,Circe 似乎确实支持 cats.data.NonEmptyMap

处理此类案例的最直接方法可能是将 Cars 案例 class 的 cars 成员更改为 Map[String, CarDetails] 这样的类型, 完全放弃 Car 案例 class。如果这样做,您的代码将完全按原样工作(减去 Car 定义),并将解码您提供的 JSON 示例。

如果您想要更接近您的案例 class 结构,您可以执行以下操作:

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 级别包含动态密钥。