jsonter, plokhotnyuk 如何使用地图将 json 解析为大小写 class

How to parse json to case class with map by jsonter, plokhotnyuk

我想从 Kafka 读取 json 消息并将它们放入 SpecificRecordBase class (avro) 的另一个结构中。 json 的部分具有动态结构,例如

{"known_type": "test", 
 "unknown_type": {"attr1": true, "attr2": "value2", "attr3": 777}}

{"known_type": "test", 
 "unknown_type": {"field1":[1,3,4,7], "field2": {"sub_field": "test"}}}

{"known_type": "test", 
"unknown_type": {"param": "some_value"}}

我想使用灵活的 table 并将其放在 Map[String, String] 中,其中每个键 = 属性名称,值 = 字符串中的属性值,并且没有验证。目标示例 classes 实例:

Example(test,Map(attr1 -> true, attr2 -> "value2", attr3 -> 777))

Example(test,Map(field1 -> [1,3,4,7], field2 -> {"sub_field" : "sub_value"}))

Example(test,Map(param -> "some_value"))

我写的代码有一个圆圈,但想得到与plokhotnyuk/jsoniter-scala一样的代码,你能帮我找到方法吗

case class Example(known_type: String = "", unknown_type: Map[String, String])

val result: Option[Example] = for {
    json       <- parse(rawJson2).toOption
    t          <- json.hcursor.downField("known_type").as[String].toOption
    map        <- json.hcursor.downField("unknown_type").as[JsonObject].toOption
    m = map.toMap.map { case (name, value) => name -> value.toString() }
} yield Example(t, m)

提出的通过问题解码测试的数据结构的可能解决方案之一:

case class Example(known_type: String = "", unknown_type: Map[String, String])
      
implicit val mapCodec: JsonValueCodec[Map[String, String]] = new JsonValueCodec[Map[String, String]] {
  override def decodeValue(in: JsonReader, default: Map[String, String]): Map[String, String] = {
    val b = in.nextToken()
    if (b == '{') {
      if (in.isNextToken('}')) nullValue
      else {
        in.rollbackToken()
        var i = 0
        val x = Map.newBuilder[String, String]
        while ({
          i += 1
          if (i > 1000) in.decodeError("too many keys") // To save from DoS attacks that exploit Scala's map vulnerability: https://github.com/scala/bug/issues/11203
          x += ((in.readKeyAsString(), new String({
            in.nextToken()
            in.rollbackToken()
            in.readRawValAsBytes()
          }, StandardCharsets.UTF_8)))
          in.isNextToken(',')
        }) ()
        if (in.isCurrentToken('}')) x.result()
        else in.objectEndOrCommaError()
      }
    } else in.readNullOrTokenError(default, '{')
  }

  override def encodeValue(x: Map[String, String], out: JsonWriter): Unit = ???

  override val nullValue: Map[String, String] = Map.empty
}

implicit val exampleCodec: JsonValueCodec[Example] = make