【问题标题】:Trouble serializing optional value class instances with json4s使用 json4s 序列化可选值类实例时遇到问题
【发布时间】:2020-01-05 16:56:47
【问题描述】:

我正在尝试使用 json4s 将带有可选值类字段的案例类序列化为 JSON。到目前为止,我无法正确呈现可选的值类字段(请参阅下面的 sn-p 示例)。

我试过json-nativejson-jackson 库,结果是一样的。

这是一个简短的独立测试

import org.json4s.DefaultFormats
import org.scalatest.FunSuite
import org.json4s.native.Serialization._

class JsonConversionsTest extends FunSuite {
  implicit val jsonFormats = DefaultFormats

  test("optional value-class instance conversion") {
    val json = writePretty(Foo(Option(Id(123)), "foo-name", Option("foo-opt"), Id(321)))

    val actual =
      """
        |{
        |  "id":{
        |    "value":123
        |  },
        |  "name":"foo-name",
        |  "optField":"foo-opt",
        |  "nonOptId":321
        |}
        |""".stripMargin.trim

    assert(json === actual)

    val correct =
      """
        |{
        |  "id": 123,
        |  "name":"foo-name",
        |  "optField":"foo-opt",
        |  "nonOptId":321
        |}
        |""".stripMargin.trim

    assert(json !== correct)
  }

}

case class Id(value: Int) extends AnyVal

case class Foo(id: Option[Id], name: String, optField: Option[String], nonOptId: Id)

我使用的是 scala 2.12 和最新的json4s-native 版本:

    "org.json4s" %% "json4s-native" % "3.6.7"

【问题讨论】:

    标签: scala json4s scala-option value-class


    【解决方案1】:

    它看起来与this 问题非常相似,似乎没有修复或评论。

    自定义序列化程序可以节省您的时间。

    object IdSerializer extends CustomSerializer[Id] ( format => (
      { case JInt(a)  => Id(a.toInt) },
      { case a: Id => JInt(a.value) }
    ))
    implicit val formats = DefaultFormats + IdSerializer
    val json = writePretty(Foo(Option(Id(123)), "foo-name", Option("foo-opt"), Id(321)))
    

    【讨论】:

    • 我在发布之前简要检查了问题跟踪器,但错过了那个。看来你的提议是目前唯一的方法。
    【解决方案2】:

    无论如何,请尝试其他选项,例如使用 jsoniter-scala 代替。它比 json4s 多 safeefficient,尤其是在美化 JSON 的序列化方面。

    添加/替换依赖项:

    libraryDependencies ++= Seq(
      "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-core"   % "0.55.2" % Compile,
      "com.github.plokhotnyuk.jsoniter-scala" %% "jsoniter-scala-macros" % "0.55.2" % Provided // required only in compile-time
    )
    

    为顶层数据结构派生一个编解码器,并用它序列化成一个字符串:

    import com.github.plokhotnyuk.jsoniter_scala.macros._
    import com.github.plokhotnyuk.jsoniter_scala.core._
    
    case class Id(value: Int) extends AnyVal
    
    case class Foo(id: Option[Id], name: String, optField: Option[String], nonOptId: Id)
    
    implicit val codec: JsonValueCodec[Foo] = JsonCodecMaker.make(CodecMakerConfig())
    
    val json = writeToString(Foo(Option(Id(123)), "foo-name", Option("foo-opt"), Id(321)), WriterConfig(indentionStep = 2))
    val correct =
      """{
        |  "id": 123,
        |  "name": "foo-name",
        |  "optField": "foo-opt",
        |  "nonOptId": 321
        |}""".stripMargin
    assert(json == correct)
    

    还有更有效的选项可以立即存储到字节数组、java.nio.ByteBuffer 或 java.io.OutputStream。

    【讨论】:

      最近更新 更多