You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用plokhotnyuk/jsoniter-scala将JSON解析为带Map的case类

使用jsoniter-scala实现含动态字段JSON的解析逻辑

步骤1:引入依赖

首先在项目构建配置中添加jsoniter-scala相关依赖,以sbt为例:

// 可根据实际使用的Scala版本替换为对应最新版
libraryDependencies ++= Seq(
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.23.2",
  "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.23.2" % Provided
)

步骤2:编写编解码逻辑

我们需要自定义unknown_type字段的反序列化规则,将动态结构的任意JSON值直接读取为原始字符串存入Map,和你原有circe实现的行为完全对齐:

import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._

// 原有目标类定义保持不变
case class Example(known_type: String = "", unknown_type: Map[String, String])

// 自定义解码器:将JSON对象的所有值直接读取为原始JSON字符串,生成Map[String, String]
implicit val dynamicMapCodec: JsonValueCodec[Map[String, String]] = new JsonValueCodec[Map[String, String]] {
  override def decodeValue(in: JsonReader, default: Map[String, String]): Map[String, String] = {
    if (in.isNextToken('{')) {
      var resMap = Map.empty[String, String]
      if (!in.isNextToken('}')) {
        in.rollbackToken()
        do {
          val key = in.readKeyAsString()
          // 直接读取当前节点的原始JSON字符串,无需解析具体类型
          val valueStr = in.readRawValAsString()
          resMap += key -> valueStr
        } while (in.isNextToken(','))
        if (!in.isCurrentToken('}')) in.objectEndOrCommaError()
      }
      resMap
    } else in.readNullOrError(default, "expected JSON object")
  }

  // 如不需要序列化能力可直接删除该方法实现,抛出异常即可
  override def encodeValue(x: Map[String, String], out: JsonWriter): Unit = {
    out.writeObjectStart()
    x.foreach { case (k, v) =>
      out.writeKey(k)
      out.writeRawVal(v)
    }
    out.writeObjectEnd()
  }

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

// 自动生成Example类的编解码器
implicit val exampleCodec: JsonValueCodec[Example] = JsonCodecMaker.make

步骤3:封装解析方法

封装和原有circe逻辑一致的返回Option的解析方法:

def parseExample(rawJson: String): Option[Example] = {
  try {
    Some(readFromString[Example](rawJson))
  } catch {
    case _: JsonReaderException => None
  }
}

效果验证

输入你给出的测试JSON即可得到完全匹配预期的结果:

val testJson = """{"known_type": "test", "unknown_type": {"attr1": true, "attr2": "value2", "attr3": 777}}"""
println(parseExample(testJson))
// 输出:Some(Example(test,Map(attr1 -> true, attr2 -> "value2", attr3 -> 777)))

内容的提问来源于stack exchange,提问作者Vadim

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 05:06:04