使用 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
级别包含动态密钥。
我试图将以下 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
级别包含动态密钥。