JsonFormat for abstract class with generic parameter
JsonFormat for abstract class with generic parameter
我正在尝试为抽象 class 编写一个 JsonFormat,其中的通用参数看起来像这样:
abstract class Animal[A] {
def data: A
def otherStuff: String = "stuff"
}
case class CatData(catField: String)
case class Cat(data: CatData) extends Animal[CatData]
到目前为止,我的尝试如下所示:
object AnimalProtocol extends DefaultJsonProtocol {
implicit val catDataFormat = jsonFormat1(CatData)
implicit val catFormat = jsonFormat1(Cat)
implicit def animalFormat[T <: Animal[T]](t: T)(implicit fmt: JsonWriter[T]) = new RootJsonFormat[Animal[T]] {
def write(obj: Animal[T]) = obj match {
case x: Cat => catFormat.write(x)
}
def read(json: JsValue) = ???
}
现在,如果我尝试这样做:
import AnimalProtocol._
val cat: Animal[CatData] = Cat(CatData("this is cat data"))
我收到编译器错误:
Cannot find JsonWriter or JsonFormat type class for Animal[CatData]
我怎样才能让它发挥作用?最后,我想用 Animal
中的字段编写 json 并将 data
设置为 class 适用的任何情况。
我不使用 spray-json(我对 play-json 有更多的经验),但我会尝试通过指出一些奇怪的事情来提供帮助你的代码。
我不确定您是否需要 implicit val catFormat = jsonFormat1(Cat)
,除非您希望在已知类型为 Cat
.
时应用它而不是 animalFormat
您对 animalFormat
的定义看起来 wrong/strange,原因如下:
- 类型很奇怪,
T <: Animal[T]
不符合您的类型,即您没有 CatData <: Animal[CatData]
- 你不使用
t
- 您不使用
fmt
(而是在 obj
上进行模式匹配)
我建议要么定义一个静态 animalFormat
,比如(不确定通配符类型 _
):
val animalFormat: RootJsonFormat[Animal[_]] = new RootJsonFormat[Animal[_]] {
def write(obj: Animal[_]) = {
JsObject(
"otherStuff" -> JsString(obj.otherStuff),
"data" -> obj match {
case x: Cat => catDataFormat.write(x.data)
}
)
def read(json: JsValue) = ???
}
或者,不使用模式匹配:
implicit def animalFormat[T](implicit fmt: JsonWriter[T]) = new RootJsonFormat[Animal[T]] {
def write(obj: Animal[T]) =
JsObject(
"otherStuff" -> JsString(obj.otherStuff),
"data" -> fmt.write(obj.data)
)
def read(json: JsValue) = ???
}
请注意,使用这种方法,您将无法读取通用 Animal
,因为 json.
中没有类型信息
您需要为 implicit def
中的通用字段和 Animal 子类提供类型参数:
object AnimalProtocol2 extends DefaultJsonProtocol {
implicit val catDataFormat = jsonFormat1(CatData)
implicit def animalFormat[A, T <: Animal[A]](implicit fmt: JsonWriter[A]): RootJsonFormat[T] = new RootJsonFormat[T] {
def write(obj: T) = {
JsObject(
"data" -> obj.data.toJson,
"otherStuff" -> obj.otherStuff.toJson
)
}
def read(json: JsValue) = ???
}
}
这还允许您摆脱 animalFormat
中子类的模式匹配。
我正在尝试为抽象 class 编写一个 JsonFormat,其中的通用参数看起来像这样:
abstract class Animal[A] {
def data: A
def otherStuff: String = "stuff"
}
case class CatData(catField: String)
case class Cat(data: CatData) extends Animal[CatData]
到目前为止,我的尝试如下所示:
object AnimalProtocol extends DefaultJsonProtocol {
implicit val catDataFormat = jsonFormat1(CatData)
implicit val catFormat = jsonFormat1(Cat)
implicit def animalFormat[T <: Animal[T]](t: T)(implicit fmt: JsonWriter[T]) = new RootJsonFormat[Animal[T]] {
def write(obj: Animal[T]) = obj match {
case x: Cat => catFormat.write(x)
}
def read(json: JsValue) = ???
}
现在,如果我尝试这样做:
import AnimalProtocol._
val cat: Animal[CatData] = Cat(CatData("this is cat data"))
我收到编译器错误:
Cannot find JsonWriter or JsonFormat type class for Animal[CatData]
我怎样才能让它发挥作用?最后,我想用 Animal
中的字段编写 json 并将 data
设置为 class 适用的任何情况。
我不使用 spray-json(我对 play-json 有更多的经验),但我会尝试通过指出一些奇怪的事情来提供帮助你的代码。
我不确定您是否需要 implicit val catFormat = jsonFormat1(Cat)
,除非您希望在已知类型为 Cat
.
animalFormat
您对 animalFormat
的定义看起来 wrong/strange,原因如下:
- 类型很奇怪,
T <: Animal[T]
不符合您的类型,即您没有CatData <: Animal[CatData]
- 你不使用
t
- 您不使用
fmt
(而是在obj
上进行模式匹配)
我建议要么定义一个静态 animalFormat
,比如(不确定通配符类型 _
):
val animalFormat: RootJsonFormat[Animal[_]] = new RootJsonFormat[Animal[_]] {
def write(obj: Animal[_]) = {
JsObject(
"otherStuff" -> JsString(obj.otherStuff),
"data" -> obj match {
case x: Cat => catDataFormat.write(x.data)
}
)
def read(json: JsValue) = ???
}
或者,不使用模式匹配:
implicit def animalFormat[T](implicit fmt: JsonWriter[T]) = new RootJsonFormat[Animal[T]] {
def write(obj: Animal[T]) =
JsObject(
"otherStuff" -> JsString(obj.otherStuff),
"data" -> fmt.write(obj.data)
)
def read(json: JsValue) = ???
}
请注意,使用这种方法,您将无法读取通用 Animal
,因为 json.
您需要为 implicit def
中的通用字段和 Animal 子类提供类型参数:
object AnimalProtocol2 extends DefaultJsonProtocol {
implicit val catDataFormat = jsonFormat1(CatData)
implicit def animalFormat[A, T <: Animal[A]](implicit fmt: JsonWriter[A]): RootJsonFormat[T] = new RootJsonFormat[T] {
def write(obj: T) = {
JsObject(
"data" -> obj.data.toJson,
"otherStuff" -> obj.otherStuff.toJson
)
}
def read(json: JsValue) = ???
}
}
这还允许您摆脱 animalFormat
中子类的模式匹配。