首页 > 解决方案 > 抽象类上的 Json.reads(不支持密封特征:没有已知的子类)

问题描述

我有一个抽象类和对象

sealed abstract class Granularity() {
  // some values and methods
}

object Granularity {
  final private case class WeekGranularity(name: String, windowSize: Int) extends Granularity("week", "'7' day") {
     // overriding methods
  }

  val Week: Granularity = WeekGranularity(name = "week", windowSize = 1)
}

我在像这样的其他课程中使用它

case class Meta(granularity: Granularity)

object Meta {
  implicit val granularityWrites = Writes[Granularity](d => JsString(d.toString))
  implicit val metaWrites = Json.writes[Meta]
}

现在在编写这样的规范时,我收到一个错误

class ControllerSpec {

  "MetaController" should {
      "return" {
         .
         .
         .
         // play 2.13 resp
         resp.body[JsValue].asOpt[Meta] should beSome(expectedMeta)
         // ERROR: No Json deserializer found for type models.Meta. Try to implement an implicit Reads or Format for this type
       }
  }
}

当我在 Spec 类的顶部添加隐式读取时,仍然出现错误

  implicit val granularityReads = Json.reads[Granularity] // ERROR: Sealed trait Granularity is not supported: no known subclasses
  implicit val metaReads = Json.reads[Meta]

我可以这样做来比较 json,它可以工作并且我不必创建任何隐式。

resp.body[JsValue] shouldEqual Json.toJson(metricSignTimeseries)

但我想了解如何实现对粒度的隐式读取?

标签: scalaimplicitplay-json

解决方案


为了Granularity从 JSON 数据中读取 a ,库必须能够创建一个实例Granularity以便返回它。但是Granularityabstract class您不能创建抽象类的实例。

Json.reads需要使用可以由库实例化的具体类进行参数化,或者您需要编写一个自定义Reads[Granularity]来创建并返回Granularity.

我建议您不要将功能放在用于读取/写入 JSON 或使用复杂类层次结构的类中。只需将数据读入case class直接匹配JSON格式的简单实例,然后处理成应用类即可。这允许存储格式和内部应用程序数据格式独立更改,而不是紧密链接。


推荐阅读