如何使用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
相关产品推荐
相关产品推荐

