JSON将Scala案例类序列化为仅字符串和整数
Posted
技术标签:
【中文标题】JSON将Scala案例类序列化为仅字符串和整数【英文标题】:JSON Serializing Scala Case Class to only strings and ints 【发布时间】:2022-01-03 04:25:09 【问题描述】:我需要将少数案例类序列化为仅字符串和整数。意思是,如果有嵌套类型,它会被序列化为 JSON 对象的字符串化版本,而不是 JSON 对象。
例子:
case class Deepest(someNum: Int)
case class Inner(superDeep: Deepest)
case class Outer(aValue: Int, aNestedValue: Inner)
序列化Outer
的实例会导致(或类似的结果)
"Outer":
"aValue": 5,
"aNestedValue": " \"superDeep\": .... "
这可能吗?
【问题讨论】:
我猜有可能,例如,如果您在 Play-Json 中编写自定义Writes[Outer]
。
【参考方案1】:
使用jsoniter-scala 是使用Scala 最简单、最有效的方法。
添加依赖:
libraryDependencies ++= Seq(
// Use the %%% operator instead of %% for Scala.js
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core" % "2.12.0",
// Use the "provided" scope instead when the "compile-internal" scope is not supported
"com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "2.12.0" % "compile-internal"
)
使用来自这个 sn-p 的自定义编解码器:
import com.github.plokhotnyuk.jsoniter_scala.macros._
import com.github.plokhotnyuk.jsoniter_scala.core._
object Example01
sealed trait Message
case class Deepest(someNum: Int)
case class Inner(superDeep: Deepest)
case class Outer(aValue: Int, aNestedValue: Inner) extends Message
implicit val innerCodec: JsonValueCodec[Inner] = new JsonValueCodec[Inner]
private val codec: JsonValueCodec[Inner] = JsonCodecMaker.make
override def decodeValue(in: JsonReader, default: Inner): Inner =
readFromStringReentrant(in.readString(null))(codec)
override def encodeValue(x: Inner, out: JsonWriter): Unit =
out.writeVal(writeToStringReentrant(x)(codec))
override def nullValue: Inner = null
implicit val messageCodec: JsonValueCodec[Message] =
JsonCodecMaker.make(CodecMakerConfig.withDiscriminatorFieldName(None))
def main(args: Array[String]): Unit =
val message = readFromString[Message](
"""
| "Outer":
| "aValue": 5,
| "aNestedValue": " \"superDeep\": \"someNum\": 1 "
|
|""".stripMargin)
println(writeToString[Message](message, WriterConfig.withIndentionStep(4)))
预期输出:
"Outer":
"aValue": 5,
"aNestedValue": "\"superDeep\":\"someNum\":1"
如果应该对多个类型进行字符串化,您可以定义一个函数,该函数采用常规编解码器并返回一个编解码器,该编解码器将原始类型的输出字符串化:
def makeStringifyingCodec[A](codec: JsonValueCodec[A]): JsonValueCodec[A] =
new JsonValueCodec[A]
override def decodeValue(in: JsonReader, default: A): A =
readFromStringReentrant(in.readString(null))(codec)
override def encodeValue(x: A, out: JsonWriter): Unit =
out.writeVal(writeToStringReentrant(x)(codec))
override def nullValue: A = null.asInstanceOf[A]
并将其用于Outer
类的字段类型:
implicit val innerCodec: JsonValueCodec[Inner] =
makeStringifyingCodec(JsonCodecMaker.make[Inner])
implicit val messageCodec: JsonValueCodec[Message] =
JsonCodecMaker.make(CodecMakerConfig.withDiscriminatorFieldName(None))
【讨论】:
以上是关于JSON将Scala案例类序列化为仅字符串和整数的主要内容,如果未能解决你的问题,请参考以下文章
使用 circe 将 Scala None 编码为 JSON 值