scala - Spray Json:从通用对象中获取 Json 字符串
问题描述
我有以下课程
import spray.json._
sealed trait Base
case class Foo[K, V](key : K, value : V) extends Base
case class Bar[K, V](key : V, value : K) extends Base
他们对应的 json 转换器
implicit def baseJsonConvertor[K: JsonFormat, V: JsonFormat] = new JsonFormat[Base] {
override def read(json: JsValue): Base =
throw new SerializationException("Don't use this for reading...")
override def write(obj: Base): JsValue = obj match {
case e : Foo[K, V] => jsonFormat2(Foo.apply[K, V]).toJson
case e : Bar[K, V] => jsonFormat2(Bar.apply[V, K]).toJson
}
}
implicit def fooJsonConvertor[K: JsonFormat, V: JsonFormat] = jsonFormat2(Foo.apply[K, V])
implicit def barJsonConvertor[K: JsonFormat, V: JsonFormat] = jsonFormat2(Bar.apply[V, K])
当我尝试这个
val list = List(Foo[String, Int]("One", 1), Bar(2, "Two") ).map(_.toJson)
我得到这个错误
:216: 警告:类型模式 Foo[K,V] 中的抽象类型 K 未选中,因为它被擦除案例 e 消除:Foo[K, V] => jsonFormat2(Foo.apply[K, V]).toJson
使用 Base val list = List(FooString, Int).map(_.toJson) 找不到具有 Serializable 的 Product 的 JsonWriter 或 JsonFormat 类型类
我不能match-case
在write
.baseJsonConvertor
有人可以帮助解决这个问题吗?
解决方案
此示例将适用于这种特殊情况:
import org.scalatest.{Matchers, WordSpecLike}
object O {
import spray.json._
import spray.json.DefaultJsonProtocol._
sealed trait Base[K, V]
case class Foo[K, V](key: K, value: V) extends Base[K, V]
case class Bar[K, V](key: V, value: K) extends Base[K, V]
implicit def fooJsonConvertor[K: JsonFormat, V: JsonFormat] = jsonFormat2(Foo.apply[K, V])
implicit def barJsonConvertor[K: JsonFormat, V: JsonFormat] = jsonFormat2(Bar.apply[V, K])
implicit def baseJsonConvertor[K: JsonFormat: Manifest, V: JsonFormat: Manifest] = new JsonFormat[Base[K, V]] {
override def read(json: JsValue): Base[K, V] =
throw new SerializationException("Don't use this for reading...")
override def write(obj: Base[K, V]): JsValue = obj match {
case e@Foo(_: K, _: V) => implicitly[JsonFormat[Foo[K,V]]].write(e.asInstanceOf[Foo[K, V]])
case e@Bar(_: V, _: K) => implicitly[JsonFormat[Bar[K,V]]].write(e.asInstanceOf[Bar[K, V]])
}
}
}
class Spec extends WordSpecLike with Matchers {
import O._
import spray.json._
import spray.json.DefaultJsonProtocol._
"test" should {
"test" in {
val list = List[Base[String, Int]](Foo[String, Int]("One", 1), Bar(2, "Two")).map(_.toJson)
println(list)
}
}
}
但是,您不能使用没有类型参数的 Base,因为没有它们您将无法派生 JsonFormat。请注意,您必须以它们使用的相反顺序声明非法 jsonFormats。我的意思是您必须首先为 JsonFormat Foo 和 Bar 声明隐式,然后再为 Base 声明。否则他们将无法被发现。您还应该使用隐式 Manifest 才能安全匹配。
如果您实际上遇到了更复杂的情况,子类中的类型参数数量可变,那么这对您不起作用。我认为在不消除子类中的类型参数的情况下,参数数量可变的情况无法有效解决。另请注意,如果对象 O 与 Spec 在同一个文件中,则必须在 Spec 之前声明包含隐式的对象 O 才能在 Spec 中可见。
推荐阅读
- regex - 使用 RE2 Regexp_Extract 在管道之间提取内容
- python-3.x - 如何确保终端搜索 venv 文件夹而不是第三方模块的默认 python 位置?
- java - Objectify 单元测试将数据持久化到 Google Cloud Datastore
- r - XML 到具有重复同级的数据框
- haskell - GHCi ":browse" 如何导入模块?
- docker - could_not_write_file cluster_nodes.config etxtbsy
- ionic-framework - 声明为能够处理“json”类型的请求但使用“http”类型的请求调用的函数
- linux - 在 Ubuntu 18.04.4 上安装 Jenkins。詹金斯没有开始
- c# - c#程序如何获取VS 2019的安装位置?
- java - jcifs - 如何将文件夹从共享文件夹复制到本地文件夹