当X从Y扩展而Y是trait时,如何在Play JSON中定义Y和List[X]的格式?

当X从Y扩展而Y是trait时,如何在Play JSON中定义Y和List[X]的格式?,json,scala,playframework,play-json,Json,Scala,Playframework,Play Json,我不能在特定情况下转换列表:当类型是从trait扩展而来时 当我可以转换时: import play.api.libs.functional.syntax_ 导入play.api.libs.json_ 密封特征项 案例类Id(Id:Long)扩展项目 案例类MyList(列表:列表[Id]) 对象MyFormat{ 隐式lazy val idFormat=Json.format[Id] 隐式lazy val myListFormat=Json.format[MyList] } 当我无法转换时:

我不能在特定情况下转换列表:当类型是从trait扩展而来时

当我可以转换时:

import play.api.libs.functional.syntax_
导入play.api.libs.json_
密封特征项
案例类Id(Id:Long)扩展项目
案例类MyList(列表:列表[Id])
对象MyFormat{
隐式lazy val idFormat=Json.format[Id]
隐式lazy val myListFormat=Json.format[MyList]
}
当我无法转换时:

密封特征项
案例类Id(Id:Long)扩展项目
案例类MyList(列表:列表[Id])
对象MyFormat{
隐式lazy val itemFormat=新格式[项目]{
重写def写入(o:Item):JsValue=o匹配{
案例一:Id=>idFormat.writes(i)
}
覆盖def读取(json:JsValue):JsResult[Item]={
idFormat.reads(json)
}
}
隐式lazy val idFormat=Json.format[Id]
隐式lazy val myListFormat=Json.format[MyList]
}
错误:
错误:(33,49)隐式作用域中的scala.collection.immutable.List[Main2.Id]没有play.api.libs.json.Format的实例可用(提示:如果在同一文件中声明,请确保之前已声明)
隐式lazy val myListFormat=Json.format[MyList]

为什么我不能在第二种情况下格式化

如果我为列表添加格式化程序:

implicit lazy val idsFormat=Json.format[List[Id]]
然后我得到了
错误:(33,46)隐式作用域中的scala.collection.immutable.Nil没有可用的读取实例(提示:如果在同一个文件中声明,请确保在前面声明)
隐式惰性val idsFormat=Json.format[List[Id]]

附言: 我找到的唯一解决方案是:

  • 列表[Id]
  • 读或写时,使用
    Id的格式
  • 阅读时,使用

  • 如果play JSON具有自动/半自动编解码器实例派生功能,那么它将使用隐式来启用这种机制。这意味着复杂事物的编解码器应该在其组件之后引入

    在您的例子中,play JSON似乎试图为List和case类i派生编解码器。E至于
    List(a1,List(a2,…,List(an,Nil))
    当它点击Nil时,它不知道如何为它派生编解码器

    我相信您不希望列表编码为折叠对象链,而是编码为JSON数组

    然后,您应该在播放源中搜索默认的
    List[T]
    codec,并尝试通过专门化
    Id
    来使用它

    调试缺少隐式的通用工具是编译器选项“-Xlog implicits”。它将把所有失败的隐式搜索记录到控制台,并且可以找出这些消息缺少的内容

    强烈建议在使用广泛使用此功能的库之前了解隐式作品

    最后,但并非最不重要的是:

    你试过使用吗?它为密封特征族和标准scala类自动和半自动JSON派生。它甚至有一个游戏框架。Circe派生消除了编写编解码器代码的最头痛的问题,但需要对隐式优先级有很强的了解才能正常工作。对其工作方式进行了描述和分析


    如果没有足够的标准版本,您也可以尝试为play json创建自己的派生版本。

    谢谢,我稍后会尝试
    def flatten[T](xs: Seq[JsResult[T]]): JsResult[List[T]] = {
      val (ss: Seq[JsSuccess[T]], fs: Seq[JsError]) = xs.partition(_.isSuccess)
      if (fs.isEmpty) JsSuccess(ss.map(_.get).toList) else fs.head
    }