【问题标题】:Create a generic Json serialization function创建一个通用的 Json 序列化函数
【发布时间】:2013-11-05 20:12:29
【问题描述】:

是否可以使用 Play Framework 2.2 在 Scala 中创建一个通用函数,将任意对象序列化为 JSON,而无需提供编写器或格式化程序?

例如,这个非通用代码将创建一个给定客户的 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"}}
}

为了避免必须为每个不同的对象定义格式化程序,我想创建一个这样的通用函数:

def createJsonResponse[T](data: T) = {
  implicit val formatter = Json.format[T]
  Json.obj("success" -> true, "data" -> Json.toJson[T](data))
}

但是这种尝试会在Json.format[T] 处产生错误No unapply function found

换句话说,这是可行的:

def getFormatter(c: Customer) = Json.format[Customer]

但这不是:

def getFormatterGeneric[T](c: T) = Json.format[T]

有没有办法解决这个问题?

【问题讨论】:

    标签: json scala generics playframework playframework-2.2


    【解决方案1】:

    您需要在某处为您希望读取或写入的每种类型定义格式化程序。这是因为格式化程序实例是在编译时解析的,而不是在运行时解析的。 这是一件好事,因为这意味着尝试序列化没有序列化程序的类型会成为编译时错误,而不是运行时错误。

    不要动态定义格式化程序,而是在可以重用的模块中定义它们,例如

    object JsonFormatters {
      implicit val customerWrites: Format[Customer] = Json.format[Customer]
    }
    

    然后import JsonFormatters._在你想写一些JSON的范围内。

    现在,您可以编写一个与您想要的类似的通用方法:您只需在方法的签名中指定对格式化程序的要求。实际上,这是Writes[T] 类型的隐式参数。

    def createJsonResponse[T](data: T)(implicit writes: Writes[T]) =
      Json.obj("success" -> true, "data" -> Json.toJson[T](data))
    

    您也可以使用上下文绑定语法编写此方法签名,即

    def createJsonResponse[T : Writes](data: T) = ...
    

    这要求范围内有Writes[T] 的实例;但编译器会根据 T 类型为您选择正确的实例,而不是您显式解析它。

    注意Writes[T]Format[T] 的超类型;由于您只是在此方法中编写 JSON,因此无需指定Format[T] 的要求,这也会为您提供Reads[T]

    【讨论】:

    • 补充一下,您可以自动创建Writes[T]implicit blahWrites = Json.Writes[Blah] (link to docs)。
    • 是的,你不能对所有类型一劳永逸的原因是Json.format是一个,它查看特定类型 并为其生成一些特定于类型的代码。它显然不能对类型参数这样做。
    • 你能举一个在play 2.8中做的完整例子吗?我对此进行了测试,但没有运气:(我想创建一个随时序列化的函数。
    猜你喜欢
    • 2020-03-14
    • 1970-01-01
    • 2017-04-25
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2016-06-22
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多