14

我已经被这个特殊问题困住了大约一个星期,我想我将把这个问题写在这里作为一个问题来清除我的想法并获得一些指导。

所以我有这个具有java.sql.Timestamp字段的案例类:

case class Request(id: Option[Int], requestDate: Timestamp)

我想将其转换为JsObject

val q = Query(Requests).list // This is Slick, a database access lib for Scala
  printList(q)    
  Ok(Json.toJson(q))   // and this is where I run into trouble

“没有找到类型 List[models.Request] 的 Json 反序列化器。尝试为此类型实现隐式写入或格式。” 好吧,这是有道理的。

因此,按照此处的 Play 文档,我尝试编写格式...

implicit val requestFormat = Json.format[Request]  // need Timestamp deserializer
implicit val timestampFormat = (
      (__ \ "time").format[Long]   // error 1
)(Timestamp.apply, unlift(Timestamp.unapply))  // error 2

错误 1

Description Resource Path Location Type overloaded method value format with alternatives:   

(w: play.api.libs.json.Writes[Long])(implicit r: play.api.libs.json.Reads[Long])play.api.libs.json.OFormat[Long] 
<and>   
(r: play.api.libs.json.Reads[Long])(implicit w: play.api.libs.json.Writes[Long])play.api.libs.json.OFormat[Long] 
<and>   
(implicit f: play.api.libs.json.Format[Long])play.api.libs.json.OFormat[Long]  
cannot be applied to (<error>, <error>)

显然像这样导入(参见文档“ctrl+F import”)让我遇到了麻烦:

import play.api.libs.json._    // so I change this to import only Format and fine
import play.api.libs.functional.syntax._
import play.api.libs.json.Json
import play.api.libs.json.Json._  

现在重载错误消失了,我遇到了更多的问题:not found: value __我已经导入.../functional.syntax._了,就像文档中所说的那样!这家伙遇到了同样的问题,但导入为他解决了这个问题!所以为什么?!play run我认为这可能只是 Eclipse 的问题,并且无论如何都尝试过......没有任何改变。美好的。编译器永远是对的。

导入play.api.lib.json.JsPath,改成__JsPath和wallah:

错误 2

value apply is not a member of object java.sql.Timestamp
value unapply is not a member of object java.sql.Timestamp


我还尝试更改策略并为此而不是格式写一个写,没有花哨的新组合器(__)功能,遵循官方文档基于/复制粘贴的原始博客文章

// I change the imports above to use Writes instead of Format
 implicit val timestampFormat = new Writes[Timestamp](  // ERROR 3
    def writes(t: Timestamp): JsValue = { // ERROR 4 def is underlined
      Json.obj(
          /* Returns the number of milliseconds since 
           January 1, 1970, 00:00:00 GMT represented by this Timestamp object. */
              "time" -> t.getTime() 
      )
    }
  )

错误 3:trait Writes is abstract, cannot be instantiated

错误 4:illegal start of simple expression

在这一点上,我已经束手无策了,所以我只是回到我的精神堆栈的其余部分,并从我的第一段代码中报告



我非常感谢任何能让我摆脱编码痛苦的人

4

1 回答 1

19

它不一定是您需要的功能applyunapply它是 a) 一个函数,可以在给定一些参数的情况下构造您需要的任何类型,以及 b) 一个将该类型的实例转换为值元组的函数(通常与输入参数匹配。)

通过 Scala 案例类免费获得的applyunapply函数恰好做到了这一点,因此使用它们很方便。但是你总是可以自己写。

通常,您可以使用匿名函数来执行此操作,如下所示:

import java.sql.Timestamp
import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val timestampFormat: Format[Timestamp] = (
  (__ \ "time").format[Long]
)((long: Long) => new Timestamp(long), (ts: Timestamp) => (ts.getTime))

然而!在这种情况下,您违反了 API 的限制,该限制阻止您编写这样的格式,只有一个值。根据此答案,此处解释了此限制。

对你来说,一种可行的方法是这个看起来更复杂的黑客:

import java.sql.Timestamp
import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val rds: Reads[Timestamp] = (__ \ "time").read[Long].map{ long => new Timestamp(long) }
implicit val wrs: Writes[Timestamp] = (__ \ "time").write[Long].contramap{ (a: Timestamp) => a.getTime }
implicit val fmt: Format[Timestamp] = Format(rds, wrs)

// Test it...
val testTime = Json.obj("time" -> 123456789)
assert(testTime.as[Timestamp] == new Timestamp(123456789))
于 2013-06-24T18:21:00.240 回答