gpt4 book ai didi

scala - 缺少序列化程序时,密封特征和对象枚举的快速 json4s 序列化

转载 作者:行者123 更新时间:2023-12-04 04:28:26 25 4
gpt4 key购买 nike

设置

我正在使用 json4s 3.2.11 和 Scala 2.11。

我有一个使用 sealed trait 定义的枚举,以及它的自定义序列化程序:

import org.json4s.CustomSerializer
import org.json4s.JsonAST.JString
import org.json4s.DefaultFormats
import org.json4s.jackson.Serialization

sealed trait Foo
case object X extends Foo
case object Y extends Foo

object FooSerializer
extends CustomSerializer[Foo](
_ =>
({
case JString("x") => X
case JString("y") => Y
}, {
case X => JString("x")
case Y => JString("y")
})
)

这很棒,并且在添加到格式时效果很好:

{
implicit val formats = DefaultFormats + FooSerializer
Serialization.write(X) // "x"
}

这很棒!

问题

如果序列化器没有添加到格式中,json4s 会使用反射来创建字段的默认表示,这对这些 object 非常没有帮助s 没有字段。它默默地这样做,似乎没有办法控制它。

{
implicit val formats = DefaultFormats
Serialization.write(X) // {}
}

这是一个问题,因为直到很久以后才有迹象表明出了什么问题。如果测试没有碰巧捕捉到这些无效/无用数据,则可能会通过网络发送或写入数据库。而且,这可能会从图书馆公开暴露,这意味着下游用户也必须记住它。

注意。这与 read 不同,失败时抛出异常,因为 Foo trait 没有任何有用的构造函数:

{
implicit val formats = DefaultFormats
Serialization.read[Foo]("\"x\"")
}

org.json4s.package$MappingException: No constructor for type Foo, JString(x)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$constructor(Extraction.scala:417)
at org.json4s.Extraction$ClassInstanceBuilder.org$json4s$Extraction$ClassInstanceBuilder$$instantiate(Extraction.scala:468)
at org.json4s.Extraction$ClassInstanceBuilder$$anonfun$result$6.apply(Extraction.scala:515)
...

问题

有没有办法禁用默认 {}格式化这些对象,还是将格式化“烘焙”到对象本身?

例如,拥有 write抛出类似 read 的异常会很好,因为它会立即将问题标记给调用者。

最佳答案

有一个旧的open issue这似乎提出了类似的问题,其中一个 contributors建议

you need to create a custom deserializer or serializer



这听起来没有开箱即用的方法来改变默认行为。

方法 1:通过 Scalastyle 禁止默认格式

尝试禁止导入 org.json4s.DefaultFormats使用 Scalastyle IllegalImportsChecker
 <check level="error" class="org.scalastyle.scalariform.IllegalImportsChecker" enabled="true">
<parameters>
<customMessage>Import from illegal package: Please use example.DefaultFormats instead of org.json4s.DefaultFormats</customMessage>
<parameter name="illegalImports"><![CDATA[org.json4s.DefaultFormats]]></parameter>
</parameters>
</check>

并提供定制 DefaultFormats像这样
package object example {
val DefaultFormats = Serialization.formats(NoTypeHints) + FooSerializer
}

这将允许我们像这样序列化 ADT
import example.DefaultFormats
implicit val formats = DefaultFormats
case class Bar(foo: Foo)
println(Serialization.write(Bar(X)))
println(Serialization.write(X))
println(Serialization.write(Y))

应该输出
{"foo":"x"}
"x"
"y"

如果我们尝试导入 org.json4s.DefaultFormats ,那么 Scalastyle 应该引发以下错误:
Import from illegal package: Please use example.DefaultFormats instead of org.json4s.DefaultFormats

方法 2:烘焙非嵌套值的序列化

也许我们可以通过定义 write 将格式“烘焙”到对象中。 Foo 中的方法委托(delegate)给 Serialization.write像这样
sealed trait Foo {
object FooSerializer extends CustomSerializer[Foo](_ =>
({
case JString("x") => X
case JString("y") => Y
}, {
case X => JString("x")
case Y => JString("y")
})
)

def write: String =
Serialization.write(this)(DefaultFormats + FooSerializer)
}
case object X extends Foo
case object Y extends Foo

注意我们如何硬编码传递 FooSerializer格式为 write .现在我们可以序列化
println(X.write)
println(Y.write)

应该输出
"x"
"y"

方法三:提供自定义 DefaultFormats旁边 org.json4s.DefaultFormats
我们也可以尝试定义自定义 DefaultFormats像这样在我们自己的包裹中
package example

object DefaultFormats extends DefaultFormats {
override val customSerializers: List[Serializer[_]] = List(FooSerializer)
}

这将允许我们像这样序列化 ADT
import example.DefaultFormats
implicit val formats = DefaultFormats
case class Bar(foo: Foo)
println(Serialization.write(Bar(X)))
println(Serialization.write(X))
println(Serialization.write(Y))

应该输出
{"foo":"x"}
"x"
"y"

有两种默认格式, org.json4s.DefaultFormatsexample.DefaultFormats ,至少会让用户不得不在两者之间进行选择,如果说,他们使用 IDE 自动导入它们。

关于scala - 缺少序列化程序时,密封特征和对象枚举的快速 json4s 序列化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55719643/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com