【问题标题】:JSON Serializing Scala Case Class to only strings and intsJSON将Scala案例类序列化为仅字符串和整数
【发布时间】: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]

标签: json scala jackson


【解决方案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))

【讨论】:

    猜你喜欢
    • 2014-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2017-03-29
    • 1970-01-01
    • 2015-05-27
    • 2020-07-13
    • 2019-03-28
    相关资源
    最近更新 更多