case类到json(部分)转换

时间:2014-06-25 22:28:20

标签: json scala playframework

我有以下案例类:

case class Test(name: String, email: String, phone: String)

因此,为了能够序列化为JSON,我写道:

implicit val testWrites: Writes[Test] = (
  (__ \ "name").write[String] and
    (__ \ "email").write[String] and
    (__ \ "phone").write[String]
  )(unlift(Test.unapply))

我想将它用作类似DTO对象的东西,所以我可以在serizalizing时排除一些字段。 我们说我想只显示nameemail字段。

我试过这样的事情:

implicit val testWrites: Writes[Test] = (
  (__ \ "name").write[String] and
    (__ \ "email").write[String]
  )(unlift(Test.unapply))

但是这给了我编译错误 - > Application does not take parameters

有谁知道问题是什么,以及如何实现上述想法?

1 个答案:

答案 0 :(得分:12)

播放JSON组合器通常会利用在案例类的伴随对象中自动生成的unapply方法。

对于您的案例类:

case class Test(name: String, email: String, phone: String)

unapply方法如下所示:

def unapply(test: Test): Option[(String, String, String)] = Some((test.name, test.email, test.phone))

它返回案例类的字段值,这些字段值由Option组成并包装。例如:

val test: Test = Test("John Sample", "fake@email.com", "1-800-NOT-NULL")

Test.unapply(test) // returns Some(("John Sample", "fake@email.com", "1-800-NOT-NULL"))

unliftunapply函数转换为PartialFunction[Test, (String, String, String)],然后将其用于将Test的实例映射到元组,然后将其用于序列化类

您无需使用Test.unapply。当您想要序列化整个类时,它只是方便使用它。如果您只想要一些字段,则可以定义类似的函数Test => Option[(String, String)]

def simpleExtractor(test: Test): Option[(String, String)] = Some(test.name, test.email)

然后在JSON组合器中使用它:

implicit val testWrites: Writes[Test] = (
    (__ \ "name").write[String] and
    (__ \ "email").write[String]
)(unlift(simpleExtractor))

类似地,JSON Reads经常利用自动生成的apply方法来处理案例类。 Test.apply _是一个函数(String, String, String) => Test - 基本上与unapply相反,正如您可能已经猜到的那样。 JSON API使用Reads中指定的字段组合一个元组,然后将该元组传递给Test.apply _,生成反序列化的Test

要生成只会读取两个字段的Reads,您可以定义另一个类似应用的函数:

def simpleBuilder(name: String, email: String): Test = Test(name, email, "default")

implicit val testReads: Reads[Test] = (
    (__ \ "name").read[String] and
    (__ \ "email").read[String]
)(unlift(simpleBuilder _))

虽然我个人不喜欢这样做,并在Reads内定义默认值:

implicit val testReads: Reads[Test] = (
    (__ \ "name").read[String] and
    (__ \ "email").read[String] and 
    (__ \ "phone").read[String].orElse(Reads.pure("default"))
)(unlift(Test.apply _))