I'm trying to serialize a case class with optional value-class field to JSON using json4s. So far, I'm not able to get the optional value-class field rendered correctly (see the snippet below with examples).
I tried json-native
and json-jackson
libraries, results are identical.
Here's a short self-contained test
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)
I'm using scala 2.12 and the latest json4s-native
version:
"org.json4s" %% "json4s-native" % "3.6.7"
It looks very similar to this issue, doesn't seem to be fixed or commented on.
A custom serializer would save your day.
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)))