如何为没有匹配构造函数签名的模型编写JSON读取?

时间:2014-05-29 17:13:15

标签: json scala playframework

我有以下JSON对象:

{"values": "123,456,789"}

我想使用play框架的JSON库将此JSON对象转换为具有以下签名的类Foo的实例:

case class Foo(value1: Double, value2: Double, value3: Double)

documentation about JSON combinators中,只有转换的示例,其中类的构造函数签名与提取的JSON值匹配。如果我遇到这种情况,我必须编写以下Reads函数:

import play.api.libs.json._
import play.api.libs.functional.syntax._

implicit val fooReads: Reads[Foo] = (
  (JsPath \ "values").read[String]
)(Foo.apply _)

但是,首先我必须将字符串"123,456,789"拆分为三个单独的字符串,并在创建类Double的实例之前将它们中的每一个转换为Foo值。如何使用JSON组合器完成此操作?我无法找到相关的例子。尝试将函数文本作为参数传递不起作用:

// this does not work
implicit val fooReads: Reads[Foo] = (
  (JsPath \ "values").read[String]
)((values: String) => {
  val Array(value1, value2, value3) = values.split(",").map(_.toDouble)
  Foo(value1, value2, value3)
})

2 个答案:

答案 0 :(得分:2)

编译器感到困惑,并认为您将函数作为(通常是隐式)参数传递给read方法。您可以通过明确使用Reads.map代替ApplicationOps.apply来解决此问题:

implicit val fooReads: Reads[Foo] = {
  (JsPath \ "values").read[String] map { values =>
    val Array(value1, value2, value3) = values.split(",").map(_.toDouble)
    Foo(value1, value2, value3)
  }
}

答案 1 :(得分:1)

或者,您可以重载伴随对象的apply方法,该方法不需要对隐式读取代码进行任何更改。相反,将字符串转换为一组值的逻辑将包含在apply中。

import play.api.libs.json._
import play.api.libs.functional.syntax._

case class Foo(value1: Double, value2: Double, value3: Double)

object Foo {
    def apply(values: String) = {
        values =>
            val Array(value1, value2, value3) = values.split(",").map(_.toDouble)
            Foo(value1, value2, value3)
    }

    implicit val fooReads: Reads[Foo] = (
      (JsPath \ "values").read[String]
    )(Foo.apply _)
}