Fer*_*eia 5 generics json scala playframework playframework-2.2
是否可以使用Play Framework 2.2在Scala中创建一个通用函数,它将任意对象序列化为JSON,而不必提供编写器或格式化程序?
例如,这个非通用代码将为Customer创建一个JSON响应:
import play.api.libs.json._
import play.api.libs.functional.syntax._
case class Customer(id: Int, name: String)
object scratch {
val p = Customer(1, "n")
//> p : Customer = Customer(1,n)
def createJsonResponseCustomer(data: Customer) = {
implicit val formatter = Json.format[Customer]
Json.obj("success" -> true, "data" -> Json.toJson[Customer](data))
}
createJsonResponseCustomer(p)
//> res0: play.api.libs.json.JsObject = {"success":true,"data":{"id":1,"name":"n"}}
}
Run Code Online (Sandbox Code Playgroud)
为了避免为每个不同的对象定义格式化程序,我想创建一个这样的通用函数:
def createJsonResponse[T](data: T) = {
implicit val formatter = Json.format[T]
Json.obj("success" -> true, "data" -> Json.toJson[T](data))
}
Run Code Online (Sandbox Code Playgroud)
但是,这种尝试产生错误No unapply function found的Json.format[T].
换句话说,这有效:
def getFormatter(c: Customer) = Json.format[Customer]
Run Code Online (Sandbox Code Playgroud)
但这不是:
def getFormatterGeneric[T](c: T) = Json.format[T]
Run Code Online (Sandbox Code Playgroud)
有没有办法解决?
Ben*_*mes 10
对于要读取或写入的每种类型,您需要在某处定义格式化程序.这是因为格式化程序实例在编译时解析,而不是在运行时解析.这是一件好事,因为这意味着尝试序列化没有序列化程序的类型会成为编译时错误,而不是运行时错误.
而不是动态定义格式化程序,而是在可以重用的模块中定义它们,例如
object JsonFormatters {
implicit val customerWrites: Format[Customer] = Json.format[Customer]
}
Run Code Online (Sandbox Code Playgroud)
然后import JsonFormatters._在您想要编写一些JSON的范围内.
现在,您可以编写一个类似于您想要的通用方法:您只需在方法的签名中指定格式化程序的要求.实际上,这是一种隐含的类型参数Writes[T].
def createJsonResponse[T](data: T)(implicit writes: Writes[T]) =
Json.obj("success" -> true, "data" -> Json.toJson[T](data))
Run Code Online (Sandbox Code Playgroud)
您也可以使用上下文绑定语法编写此方法签名,即
def createJsonResponse[T : Writes](data: T) = ...
Run Code Online (Sandbox Code Playgroud)
这要求有一个Writes[T]范围的实例; 但是编译器会根据类型为您选择正确的实例T,而不是您明确地解析它.
注意,这Writes[T]是一个超类型Format[T]; 因为你只是在这个方法中编写 JSON,所以没有必要指定一个要求Format[T],这也可以给你Reads[T].