huo*_*uon 9 reflection serialization scala json4s
我正在使用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")
})
)
Run Code Online (Sandbox Code Playgroud)
这很棒,添加到以下格式后效果很好:
{
implicit val formats = DefaultFormats + FooSerializer
Serialization.write(X) // "x"
}
Run Code Online (Sandbox Code Playgroud)
这很棒!
如果未将序列化程序添加到格式中,则json4s将使用反射来创建字段的默认表示形式,这对于这些object没有字段的s 极为不利。它无声地执行此操作,似乎无法控制它。
{
implicit val formats = DefaultFormats
Serialization.write(X) // {}
}
Run Code Online (Sandbox Code Playgroud)
这是一个问题,因为直到很久以后才有迹象表明出了什么问题。如果没有碰巧捕获到这些无效/无用的数据,它们可能会通过网络发送或写入数据库。而且,这可能是从图书馆公开公开的,这意味着下游用户也必须记住它。
注意 这与不同read,后者会在失败时引发异常,因为Footrait没有任何有用的构造函数:
{
implicit val formats = DefaultFormats
Serialization.read[Foo]("\"x\"")
}
Run Code Online (Sandbox Code Playgroud)
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)
...
Run Code Online (Sandbox Code Playgroud)
有没有一种方法可以禁用{}这些对象的默认格式,或者将格式“烘焙”到对象本身?
例如,write抛出类似read这样的异常会很好,因为它会立即将问题标记给调用方。
有一个古老的开放问题似乎提出了类似的问题,其中一位贡献者建议
您需要创建自定义解串器或序列化器
这听起来没有现成的方法可以改变默认行为。
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>
Run Code Online (Sandbox Code Playgroud)
DefaultFormats并像这样提供定制
package object example {
val DefaultFormats = Serialization.formats(NoTypeHints) + FooSerializer
}
Run Code Online (Sandbox Code Playgroud)
这将允许我们像这样序列化 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))
Run Code Online (Sandbox Code Playgroud)
哪个应该输出
{"foo":"x"}
"x"
"y"
Run Code Online (Sandbox Code Playgroud)
如果我们尝试 import org.json4s.DefaultFormats,那么 Scalastyle 应该会引发以下错误:
Import from illegal package: Please use example.DefaultFormats instead of org.json4s.DefaultFormats
Run Code Online (Sandbox Code Playgroud)
也许我们可以通过定义委托的write方法将格式“烘焙”到对象中FooSerialization.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
Run Code Online (Sandbox Code Playgroud)
请注意我们如何将传递FooSerializer格式硬编码为write. 现在我们可以序列化
println(X.write)
println(Y.write)
Run Code Online (Sandbox Code Playgroud)
哪个应该输出
"x"
"y"
Run Code Online (Sandbox Code Playgroud)
DefaultFormats旁边org.json4s.DefaultFormats我们也可以尝试DefaultFormats在我们自己的包中定义自定义,如下所示
package example
object DefaultFormats extends DefaultFormats {
override val customSerializers: List[Serializer[_]] = List(FooSerializer)
}
Run Code Online (Sandbox Code Playgroud)
这将允许我们像这样序列化 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))
Run Code Online (Sandbox Code Playgroud)
哪个应该输出
{"foo":"x"}
"x"
"y"
Run Code Online (Sandbox Code Playgroud)
有两种默认格式org.json4s.DefaultFormats和example.DefaultFormats,至少会让用户必须在两者之间进行选择,如果说他们使用 IDE 自动导入它们。
| 归档时间: |
|
| 查看次数: |
202 次 |
| 最近记录: |