我有一个包含密码字段的case类。为了安全起见,我需要在转换为Json时对其进行屏蔽,所以我为此创建了一个自定义的序列器,如下所示。
import org.json4s.CustomSerializer
import org.json4s._
import scala.runtime.ScalaRunTime
import org.json4s.jackson.JsonMethods._
case class UserInfo(
userid: Long,
username: Option[String],
password: Option[String]
) {
override def toString: String = {
val ui = this.copy(password = password.map(_ => "******"))
ScalaRunTime._toString(ui)
}
}
case object UserInfoSerializer extends CustomSerializer[UserInfo](format => ({
case jsonObj: JObject =>
implicit val formats = DefaultFormats
jsonObj.extract[UserInfo]
}, {
case ui: UserInfo =>
implicit val formats = DefaultFormats
Extraction.decompose(ui.copy(password = ui.password.map(_ => "******")))
}))
implicit val formats = DefaultFormats + UserInfoSerializer
但是当我尝试转换 val ui = UserInfo(123, Some("anonymous"), Some("xxx"))
到一个Json字符串,通过 write(render(ui))
,它总是失败的
scala> render(ui)
<console>:22: error: type mismatch;
found : UserInfo
required: org.json4s.JValue
(which expands to) org.json4s.JsonAST.JValue
render(ui)
我必须用它作为 render(Extraction.decompose(ui))
或添加一个隐式转换,从 UserInfo
到 JValue
作为 implicit def userInfo2JValue(ui: UserInfn) = Extraction.decompose(ui)
有什么办法可以让自定义序列器和默认序列器一样工作?
方法 render()
只是简单地渲染JSON AST,它不知道如何将你的类的实例转换为JValue。看看这个 图谱,它说明了用Json4s进行数据转换。长话短说,如果你想把你的类渲染成JSON字符串,你可以先把它转换为JValue,然后像你一样渲染。
render(Extraction.decompose(ui))
或者你可以走捷径,使用 Serialization.write
在内部完成这两种操作。
Serialization.write(ui)
不管是哪种情况,它都会使用你的自定义序列器,如果它已经添加了显式格式。