如何为Java库中没有apply方法的对象编写JSON格式?

问题描述 投票:14回答:1

我已经在这个特定问题上停留了大约一个星期,我想在这里将其写成一个问题,以阐明我的想法并获得一些指导。

所以我有一个具有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解串器。请尝试为此类型实现隐式Writes或Format。”好的,那很有道理。

所以在Play documentation here之后,我尝试编写格式...

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

显然像这样导入(请参阅documentation“ ctrl + F导入”)使我陷入麻烦:

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._This guy遇到了同样的问题,但是导入为他解决了!所以为什么?!我认为这可能只是Eclipse的问题,并且无论如何都尝试play run ...没什么改变。精细。编译器总是正确的。

导入的play.api.lib.json.JsPath,将__更改为JsPath,并添加了Wallah:

错误2

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

[我也尝试通过改变大头钉并为此写一个Write(而不是Format),而没有遵循__的新功能(original blog post the official docs are based on/copy-pasted from):

// 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

至此,我才刚刚起步,所以我将回到我的其余部分,并从第一段代码中进行报告

我对任何可以让我摆脱编码痛苦的人表示感谢

java scala playframework playframework-2.0
1个回答
19
投票

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

使用Scala case类免费获得的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的限制,该API会阻止您编写仅具有一个值的格式。根据here解释了此限制this answer

对您来说,一种可行的方法是使外观看起来更复杂:

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))
© www.soinside.com 2019 - 2024. All rights reserved.