使用Circe进行“动态”JSON解码

时间:2018-05-22 23:44:13

标签: json scala circe

考虑这个JSON:

{
  "myDocument": {
    "static_key": "value",
    "dynamic_key": "value",
    "static_key2": "value2",
    "dynamic_key2": {
      "dynamic_key3": "value3"
    }
  }
}

我将要处理的JSON文档有一些静态密钥(我知道将永远存在的字段),但有一些其他可能存在或不存在的情况,事先不知道用于映射它们的名称某些case class

我有一个String字段的绝对路径(从存储在数据库中的配置中检索),具有以下结构:

"myDocument.dynamic_key2.dynamic_key3"

我知道我需要有一个ADT来回来回映射,所以我来到了这个:

sealed trait Data

final case class StringTuple(key: String, value: String) extends Data

object StringTuple {

  implicit val encoder: Encoder[StringTuple] = deriveEncoder[StringTuple]
  implicit val decoder: Decoder[StringTuple] = deriveDecoder[StringTuple]
}

final case class NumericTuple(key: String, value: Double) extends Data

object NumericTuple {

  implicit val encoder: Encoder[NumericTuple] = deriveEncoder[NumericTuple]
  implicit val decoder: Decoder[NumericTuple] = deriveDecoder[NumericTuple]
}

final case class DateTuple(key: String, value: OffsetDateTime) extends Data

object DateTuple {

  implicit val encoder: Encoder[DateTuple] = deriveEncoder[DateTuple]
  implicit val decoder: Decoder[DateTuple] = deriveDecoder[DateTuple]
}

final case class TransformedJson(data: Data*)

object TransformedJson {

  def apply(data: Data*): TransformedJson = new TransformedJson(data: _*)

  implicit val encoder: Encoder[TransformedJson] = deriveEncoder[TransformedJson]
  implicit val decoder: Decoder[TransformedJson] = deriveDecoder[TransformedJson]
}

基于此discussion,将Map[String, Any]与circe一起使用是没有意义的,因此我将解析单个字段时遇到的三个可能的键值案例分开:

  • 一个数字字段,我将要解析为Double
  • 按字符串字段解析(String)。
  • 解析为OffsetDateTime的日期字段。

出于这个原因,我创建了三个用于对这些组合进行建模的案例类(NumericTupleStringTupleDateTuple),我的想法是生成这样的输出JSON:< / p>

{
  "dynamic_key": "extractedValue",
  "dynamic_key3": "extractedValue3",
  ...
}

(“普通”,完全没有嵌套)。

我的想法是创建一个Data对象列表来实现这一点,我有类似的东西:

def extractValue(confElement: Conf, json: String) = {
    val cursor: HCursor = parse(json).getOrElse(Json.Null).hcursor
    val decodeDynamicParam = Decoder[NumericTuple].prepare(
      /*
          Here I think (not sure) that I can extract the value with the decoder,
          but, how can I extract the key name and set it, alongside with the extracted
          value?
       */
      _.downField(confElement.path)
    )
  }

一些注意事项:

  1. Based on Travis' response to this question我正在尝试尽可能地为JSON建模以便使用circe。这就是我尝试使用元组模型的原因。
  2. Based (again) on Travis's response to this SO question是我正在尝试使用Decode.prepare(...)方法。这是我的问题......
  3. 问题:如何提取当前光标位置的特定键名并将其映射到Tuple? 我只需要当前密钥,而不是.keys ACursor方法返回的所有密钥集。使用该键,我想手动映射具有当前键名和提取值的元组。

    总结起来,我需要转换一个具有一些未知键(名称和位置)的结构,根据我拥有的绝对点分隔路径提取它们的值,并提升键名和值命名为我后缀为Tuple的案例类。

    你能否解释一下这个问题?

    由于

0 个答案:

没有答案