在 Scala (Play Framework) 中将对象序列化为 JSON 原始类型
Serialize objects as JSON primitive type in Scala (Play Framework)
查看以下示例:
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]
好吧,这段代码无法运行,因为我没有为我的类型“MyTrait”创建 JSON 序列化程序。我可以按照 Play Framework 在文档中向我们展示的方式来做,但它会使 json 看起来像
{ value: { whatever: 1 } }
我希望它看起来像
{ value: 1 }
简而言之,我希望我的 MyTrait 对象被解释为原始类型 (Int) 而不是嵌套的 Json 对象。
如果有人能帮助我,我将不胜感激。
提前致谢!
documentation 指示如何提供自定义 Writes
,MyTrait
仅序列化它的内部 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) }
}
然后在序列化 MyTrait
实例时(注意下面的类型归属是必需的,因为 Writes
是不变的):
Json.toJson(A: MyTrait)
// --> res2: play.api.libs.json.JsValue = 0
等等 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}
我宁愿推荐看看 Enumeratum for the enumerated type MyTrait
, or to refactor MyTrait
as a Value class 并使用 Json.valueFormat
如下。
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}
查看以下示例:
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]
好吧,这段代码无法运行,因为我没有为我的类型“MyTrait”创建 JSON 序列化程序。我可以按照 Play Framework 在文档中向我们展示的方式来做,但它会使 json 看起来像
{ value: { whatever: 1 } }
我希望它看起来像
{ value: 1 }
简而言之,我希望我的 MyTrait 对象被解释为原始类型 (Int) 而不是嵌套的 Json 对象。
如果有人能帮助我,我将不胜感激。 提前致谢!
documentation 指示如何提供自定义 Writes
,MyTrait
仅序列化它的内部 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) }
}
然后在序列化 MyTrait
实例时(注意下面的类型归属是必需的,因为 Writes
是不变的):
Json.toJson(A: MyTrait)
// --> res2: play.api.libs.json.JsValue = 0
等等 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}
我宁愿推荐看看 Enumeratum for the enumerated type MyTrait
, or to refactor MyTrait
as a Value class 并使用 Json.valueFormat
如下。
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}