check out the following example:
object MyTrait {
def apply(value: Int): MyTrait = value match {
case 0 => A
case 1 => B
case 2 => C
case _ => C
}
def unapply(arg: MyTrait): Int = arg.value
}
case object A extends MyTrait {
val value = 0
}
case object B extends MyTrait {
val value = 1
}
case object C extends MyTrait {
val value = 2
}
case class Test(value: MyTrait)
implicit val testFormatter = Json.format[Test]
all right, this code won't work because i didn't create a JSON serializer for my type "MyTrait". I could do it the way the Play Framework show us to do in the documentation, but it would make a json looking like
{ value: { whatever: 1 } }
and i would like it to look like
{ value: 1 }
In short, i would like my MyTrait objetcs to be interpreted as primitive types (Int) instead of a nested Json Oject.
If someone could help me with that i would be greatful. Thank you by advance!
The documentation indicates how to provide custom Writes
, there to MyTrait
to serialize only it's inner value
.
sealed trait MyTrait {
def value: Int
}
case object A extends MyTrait {
val value = 0
}
case object B extends MyTrait {
val value = 1
}
case object C extends MyTrait {
val value = 2
}
object MyTrait {
import play.api.libs.json._
def apply(value: Int): MyTrait = value match {
case 0 => A
case 1 => B
case 2 => C
case _ => C
}
def unapply(arg: MyTrait): Int = arg.value
// ---v
implicit val writes: Writes[MyTrait] =
Writes[MyTrait] { v => JsNumber(v.value) }
}
Then when serializing MyTrait
instances (note the type ascription bellow is required as Writes
is invariant):
Json.toJson(A: MyTrait)
// --> res2: play.api.libs.json.JsValue = 0
And so about Test
class:
case class Test(value: MyTrait)
object Test {
import play.api.libs.json._
implicit val writes: OWrites[Test] = Json.writes[Test]
}
Json.toJson(Test(A))
// ---> res1: play.api.libs.json.JsValue = {"value":0}
I would rather recommend to have a look at Enumeratum for the enumerated type MyTrait
, or to refactor MyTrait
as a Value class and use Json.valueFormat
as below.
import play.api.libs.json._
final class MyTrait private(val value: Int) extends AnyVal
object MyTrait {
val A = new MyTrait(0)
val B = new MyTrait(1)
val C = new MyTrait(2)
implicit val format: Format[MyTrait] = Json.valueFormat[MyTrait]
}
case class Test(value: MyTrait)
object Test {
implicit val format: OFormat[Test] = Json.format
}
scala> Json.toJson(Test(MyTrait.A))
res0: play.api.libs.json.JsValue = {"value":0}