Scala 使用引用基类的子类为类层次结构喷涂json格式

Scala 使用引用基类的子类为类层次结构喷涂json格式,scala,spray-json,Scala,Spray Json,我有一个表示过滤器类型的类层次结构,其中一个类型包含一个基类型列表。我不知道如何为这些类型设置spray json格式,因为基类型和包含类型的格式化程序需要相互引用 让我们从类层次结构和json格式开始,其中有问题的部分被注释掉: object Filters { sealed trait Filter case class SimpleFilter(foo: String) extends Filter case class DoubleFilter(foo: String, ba

我有一个表示过滤器类型的类层次结构,其中一个类型包含一个基类型列表。我不知道如何为这些类型设置spray json格式,因为基类型和包含类型的格式化程序需要相互引用

让我们从类层次结构和json格式开始,其中有问题的部分被注释掉:

object Filters {
  sealed trait Filter
  case class SimpleFilter(foo: String) extends Filter
  case class DoubleFilter(foo: String, bar: String) extends Filter
  implicit val simpleFormat = jsonFormat1(SimpleFilter)
  implicit val doubleFormat = jsonFormat2(DoubleFilter)

//  case class AndFilter(filters: List[Filter]) extends Filter
//  implicit val andFormat = lazyFormat(jsonFormat1(AndFilter))    

  // (would really use a type field, keeping simple for example)
  implicit val filterFormat = new RootJsonFormat[Filter] {
    override def write(obj: Filter): JsValue = obj match {
      case x: SimpleFilter => x.toJson
      case x: DoubleFilter => x.toJson
//    case x: AndFilter => x.toJson
    }

    override def read(json: JsValue): Filter = json.asJsObject.getFields("bar") match {
      case Seq(_) => json.convertTo[DoubleFilter]
      case Seq()  => json.convertTo[SimpleFilter]
    }
  }
}
这编译和工作如预期,我可以序列化和反序列化具体的过滤器子类作为过滤器没有问题

但是让我们在
和filter
中进行评论。现在有麻烦了!由于在
filternformat
之前声明了
和格式
(如上所述),它将不会编译,因为
和格式
需要
filternformat

错误:(17,43)找不到spray.json.DefaultJsonProtocol.JF[List[classpath.Filters.Filter]]类型的证据参数的隐式值 隐式val andFormat=jsonFormat1(AndFilter)

filtermerformat
之后将顺序切换到
和format
,这样可以编译内容。当然,我还想在write方法中添加
和format
-引用子句到
filter
格式,即
case x:AndFilter=>x.toJson
,以及read方法中包括
json.convertTo[AndFilter]
的任何内容。这也不会编译:

错误:(23,34)找不到classpath.Filters.Filter和classpath.Filters.AndFilter的JsonWriter或JsonFormat类型类 案例x:AndFilter=>x.toJson


我找不到任何办法来解决这个问题。我尝试过spray json的
lazyFormat
,但没有帮助(只适用于递归自引用,而不是像这样的交叉引用)。有什么想法吗?

有时候你需要帮助编译器一点。在
filtermerformat
上添加显式类型和显式
write
将使其编译

sealed trait Filter
case class SimpleFilter(foo: String) extends Filter
case class DoubleFilter(foo: String, bar: String) extends Filter
case class AndFilter(filters: List[Filter])
implicit val simpleFormat = jsonFormat1(SimpleFilter)
implicit val doubleFormat = jsonFormat2(DoubleFilter)
implicit val andFormat    = jsonFormat1(AndFilter)

implicit val filterFormat: RootJsonFormat[Filter] = new RootJsonFormat[Filter] {
  override def write(obj: Filter): JsValue = obj match {
    case x: SimpleFilter => x.toJson
    case x: DoubleFilter => x.toJson
    case x: AndFilter    => andFormat.write(x)
  }

  override def read(json: JsValue): Filter = json.asJsObject.getFields("bar") match {
    case Seq(_) => json.convertTo[DoubleFilter]
    case Seq()  => json.convertTo[SimpleFilter]
  }
}

我相信下面的修改通过问题中所述的
JsonFormat[AndFilter]
的隐式解析解决了这个问题

隐式val和格式:JsonFormat[AndFilter]=lazyFormat(jsonFormat1(AndFilter))
请注意,我们需要为
提供显式类型注释(即
JsonFormat[AddFilter]
),以便
SparyJsonSupport
可以将其作为
RootJsonFormat
的实例,而不是
lazyFormat
返回的
JsonFormat

import spray.json_
导入DefaultJsonProtocol_
对象过滤器{
密封特性滤波器
case类SimpleFilter(foo:String)扩展了过滤器
case类DoubleFilter(foo:String,bar:String)扩展了过滤器
案例类和过滤器(过滤器:列表[Filter])扩展过滤器
隐式val simpleFormat=jsonFormat1(SimpleFilter)
隐式val doubleFormat=jsonFormat2(双过滤器)
隐式val andFormat:JsonFormat[AndFilter]=lazyFormat(jsonFormat1(AndFilter))
隐式val filtermerformat=new RootJsonFormat[Filter]{
覆盖def写入(obj:过滤器):JsValue=???
覆盖def读取(json:JsValue):过滤器=???
}
}

详情请参阅

哦。哼!(在我的辩护中,我已经建立了一个协议,并在几个层次结构中建立了几十个case类,但有点忘记了事情不必是隐式的。:))不幸的是,虽然这样编译,但它不起作用。尝试序列化
和过滤器
会在
spray.json.CollectionFormats
中抛出空指针异常,调用
spray.json.PimpedAny.toJson
,其中隐式的
JsonWriter
(应该是过滤器格式)为空。旁注-Pim复制的我的原始代码忽略了
和Filter
扩展
Filter
。我来编辑,太好了!当我最初使用它时,我曾尝试使用
lazyFormat
,但可能没有显式类型注释?或者是其他一些用户错误——无论如何,我都无法让它工作。谢谢你的解决方案!