【问题标题】:How to represent dynamic JSON keys in Scala when using circe使用 circe 时如何在 Scala 中表示动态 JSON 键
【发布时间】:2019-06-03 05:48:57
【问题描述】:

我正在尝试将以下 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)

【问题讨论】:

  • 如何“动态”是关键?来自一组/有限的可能性列表或“任何有效字符串”?如果是前者,您可以使用sealed trait 和几个实现。如果是后者,则将Car 建模为一个元组或将Cars 作为一个整体建模为Map
  • 谢谢,密钥可以是任何有效的字符串

标签: scala circe


【解决方案1】:

我认为您可以使用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

【讨论】:

  • 赞成,如果没有特别的理由需要 Car 案例类级别,这是最好的解决方案。
【解决方案2】:

处理此类案例的最直接方法可能是将Cars 案例类的cars 成员更改为具有类似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 级别中包含动态键。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-07-06
    • 2019-03-12
    • 2020-06-08
    • 2017-10-03
    • 2019-04-06
    • 2021-08-25
    • 2021-11-11
    相关资源
    最近更新 更多