案例类到JSON(部分)转换

4

我有以下案例类:

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对象的东西,以便在序列化时排除某些字段。 让我们假设我只想显示nameemail字段。

我尝试了以下代码:

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

但是这给我编译错误——> 应用程序不接受参数。有人知道问题是什么,以及我如何实现所提到的想法吗?

1
原因在于unapply方法返回指定的元组,因此您必须使用占位符填充空缺。 - Alex
1个回答

12

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"))

unliftunapply函数转换为一个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 _))

你能否请详细解释一下这部分内容:“它返回元组的 case class 字段值,并用 Option 包装。unlift 将 unapply 函数转换为 PartialFunction[Test,(String,String,String)],然后用于将 Test 的实例映射到元组,进而序列化该类。”。在哪里称之为将“Test”类的实例映射到元组的“mapping”,并且语句的执行顺序是什么?我是 Scala 的新手,这个语法对我来说相当困惑。 - user232343
JSON API会为您完成大部分工作。关键是要理解它从您那里寻找什么。在这种情况下,需要一个类似于unapply的函数,返回一个可选元组。我建议在REPL中尝试一些操作。如果您运行play console,您将能够使用Play libs执行所有此代码并查看返回类型。(或者如果是2.3,则运行activator console) - Michael Zajac

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接