抽象类上的 Json.reads(不支持密封特征:没有已知的子类)

Posted

技术标签:

【中文标题】抽象类上的 Json.reads(不支持密封特征:没有已知的子类)【英文标题】:Json.reads on abstract class (Sealed trait is not supported: no known subclasses) 【发布时间】:2021-10-21 11:44:16 【问题描述】:

我有一个抽象类和对象

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)

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

【问题讨论】:

你有理由不为WeekGranularity定义Reads吗? 【参考方案1】:

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

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

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

【讨论】:

以上是关于抽象类上的 Json.reads(不支持密封特征:没有已知的子类)的主要内容,如果未能解决你的问题,请参考以下文章

kotlin抽象类密封类接口

Scala的密封抽象与抽象类

在密封类中为抽象 val 赋值

C#与Java在继承静态类上的区别

C# 中基类,虚类,抽象类,密封类,接口的区别

类(抽象类与非抽象类)和接口