Play JSON combinator通常利用案例类的伴生对象中自动生成的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"))
unlift
将unapply
函数转换为一个PartialFunction[Test, (String, String, String)]
,然后用于将Test
的实例映射到元组,并用该元组序列化该类。
如果只想要一些字段,可以定义一个类似的函数Test => Option[(String, String)]
,不需要使用Test.unapply
,它只在您希望序列化整个类时才方便使用。
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
经常利用为case类自动生成的
apply
方法。
Test.apply _
是一个函数
(String, String, String) => Test
--基本上是与
unapply
相反的操作,正如你所猜想的那样。JSON API将使用在
Reads
中指定的字段来组装一个元组,然后将该元组传递到
Test.apply _
中,生成反序列化的
Test
。
要生成一个只读取两个字段的
Reads
,您可以定义另一个类似于apply的函数:
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 _))