I have a case class containing a field of password. For safety I need to mask it when converting to Json. So I create a custom serializer for this, as below.
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
But when I try to convert val ui = UserInfo(123, Some("anonymous"), Some("xxx"))
to a Json string by write(render(ui))
, it always fails with
scala> render(ui)
<console>:22: error: type mismatch;
found : UserInfo
required: org.json4s.JValue
(which expands to) org.json4s.JsonAST.JValue
render(ui)
I have to use it as render(Extraction.decompose(ui))
, or add an implicit conversion from UserInfo
to JValue
as implicit def userInfo2JValue(ui: UserInfn) = Extraction.decompose(ui)
What's the right way to make the custom serializer work as default ones?