Implicit serializing case class to Json with play.api.libs.json

时间:2017-08-30 20:28:32

标签: json scala serialization playframework format

This is my case class Response api model that must be transformed to json(Play 2.5):

2D

The problem is: When I have very deeply nested response structure, I need implement companion object for each case class in my model, and add implicit format, that looking very similar.

I looking for a mechanism that permit to me write it one time and use it for any case class. I can't switch form play.api.libs.json library.

Any idea about it?

1 个答案:

答案 0 :(得分:3)

好的,我会告诉你如何做你想做的事情,然后我会告诉你为什么你不应该这样做。

如果您想为自动生成格式,那么您只需要实现一个隐式宏。我们需要区分我们想要为其自动生成格式的类型,如果您只为Any创建,那么它将覆盖String之类的内容,这会很糟糕。因此,我们将定义一个所有案例类都将实现的特征:

trait ImplicitJsonFormat

现在我们为它实现隐式宏:

import play.api.libs.json._
import scala.language.experimental.macros

trait JsonImplicits {
  // This works for Play 2.5, in Play 2.6 it becomes JsMacroImpl.implicitConfigFormatImpl
  implicit def implicitJsonFormat[A <: ImplicitJsonFormat]: OFormat[A] = macro JsMacroImpl.formatImpl[A]
}

现在,您想要自动生成格式的任何内容,您只需要扩展ImplicitJsonFormat,并确保隐式格式混合了JsonImplicits的所有内容:

import play.api.libs.json.{Json, OFormat}

case class ResponseModel(content: NestedCaseClassModel)

object ResponseModel extends JsonImplicits {
  implicit val format: OFormat[ResponseModel] = Json.format
}

case class NestedCaseClassModel(value: String) extends ImplicitJsonFormat

你有它,NestedCaseClassModel自动生成格式。当然,您也可以自动生成ResponseModel的格式。

但你真的不应该这样做。为什么?有时明确有价值。这些json结构并不是偶然的事情,没有相关性。它们构成了REST API的协议,或者您正在使用的协议。这通常是您想要明确的内容,并且在整个代码库中保持一致。通过在每个伴随类型上明确定义格式,您可以获得这个一致的位置,并查看格式是什么。当你需要自定义它时,你可以用手动格式声明替换宏,并且你没有改变你声明格式的方法,答案仍然在于去看看格式字段。伴侣对象。

当然,当您预先创建项目时,声明所有这些格式可能会有点单调乏味。但这是其中一件容易做到的事情,很容易做对,而且一旦完成它就完成了。随着您的代码库不断发展和进步,您可能会在配套对象中找到其他内容,并且您将发现自己需要改进格式,并在迁移代码库和模式时远离宏。你的协议在不同的方向。