创建一个通用的Json序列化函数 [英] Create a generic Json serialization function

查看:142
本文介绍了创建一个通用的Json序列化函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



例如,这个非泛型代码将为客户创建一个JSON响应:

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

case类Customer(id:Int,name:String)

对象scratch {
val p = Customer(1,n)
//> p:Customer = Customer(1,n)

def createJsonResponseCustomer(data:Customer)= {
implicit val formatter = Json.format [Customer]
Json.obj(成功 - > true,data - > Json.toJson [Customer](data))
}

createJsonResponseCustomer(p)
//>数据:{id:1,name:n}}
}

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

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

但是这种尝试会产生错误找不到未应用函数在 Json.format [T]



换句话说,这是有效的:

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

t:

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

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

解决方案

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



不是定义格式化器,而是将它们定义在可重用的模块中,例如

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

然后在要编写JSON的范围内输入JsonFormatters ._



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

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

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



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

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



注意 Writes [T] 是一个超类型格式[T] ;由于您只是在此方法中编写JSON,因此不需要指定 Format [T] 的要求,这也会给您读取[T]


Is it possible to create a generic function in Scala, using Play Framework 2.2, that will serialize an arbitrary object to JSON, without having to be supplied a writer or formatter?

For instance, this non-generic code will create a JSON response given a Customer:

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"}}
}

To avoid having to define the formatter for each different object, I'd like to create a generic function like this:

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

But this attempt produces the error No unapply function found at Json.format[T].

In other words, this works:

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

but this doesn't:

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

Is there any way around this?

解决方案

You need to define the formatter somewhere, for each type you wish to read or write. This is because the formatter instances are resolved at compile time, not at runtime. This is a good thing, because it means trying to serialize a type that does not have a serializer becomes a compile-time error, not a runtime one.

Instead of defining the formatters on the fly, define them in a module that you can reuse, e.g.

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

Then import JsonFormatters._ in the scope that you want to write some JSON.

Now, you can write a generic method similar to what you wanted: you just have to specify the requirement for a formatter in the signature of your method. In practice, this is an implicit paramter of type Writes[T].

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

You can also write this method signature using context bound syntax, i.e.

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

This requires that there is an instance of Writes[T] in scope; but the compiler will choose the correct instance for you based on the type T, rather than you resolving it explicitly.

Note that Writes[T] is a supertype of Format[T]; since you are only writing JSON in this method, there's no need to specify a requirement for Format[T], which would also give you Reads[T].

这篇关于创建一个通用的Json序列化函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆