spray-json 找不到 List[T] 类型的 JsonReader

Posted

技术标签:

【中文标题】spray-json 找不到 List[T] 类型的 JsonReader【英文标题】:spray-json can't find JsonReader for type List[T] 【发布时间】:2016-09-22 11:48:58 【问题描述】:

我正在为案例类创建自定义 json 阅读器,但它找不到用于其他案例类的 List[T] 的隐式 JsonReader 类型类。

当我检查 DefaultJsonProtocol 时,它已经具有集合的隐式格式;

  implicit def listFormat[T :JsonFormat] = new RootJsonFormat[List[T]] 
    def write(list: List[T]) = JsArray(list.map(_.toJson).toVector)
    def read(value: JsValue): List[T] = value match 
      case JsArray(elements) => elements.map(_.convertTo[T])(collection.breakOut)
      case x => deserializationError("Expected List as JsArray, but got " + x)
    
  

这里是简化的代码;

case class Test(i: Int, d: Double)
case class ListOfTest(t: List[Test])

trait TestResultFormat extends DefaultJsonProtocol 

  import CustomFormat._

    implicit object TestJsonFormat extends RootJsonReader[Test] 

    override def read(json: JsValue): Test = 

      val jsObject = json.asJsObject
      val jsFields = jsObject.fields

      val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
      val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)

      Test(i, d)
    
  

  implicit object ListOfTestJsonFormat extends RootJsonReader[ListOfTest] 

    override def read(json: JsValue): ListOfTest = 

      val jsObject = json.asJsObject
      val jsFields = jsObject.fields

      val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)

      ListOfTest(tests)
    
  


这是错误;

Error:(230, 53) not enough arguments for method convertTo: (implicit evidence$1: spray.json.JsonReader[List[com.xx.Test]])List[com.xx.Test].
Unspecified value parameter evidence$1.
      val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
                                                    ^
Error:(230, 53) Cannot find JsonReader or JsonFormat type class for List[com.xx.Test]
      val tests = jsFields.get("hs").map(_.convertTo[List[Test]]).getOrElse(List.empty)
                                                ^

【问题讨论】:

【参考方案1】:

我认为问题与DefaultJsonProtocolList[T]JsonReaderRootJsonFormat(不是RootJsonReader)这一事实有关,这基本上意味着您可以阅读它也可以编写它。因此,当您尝试读取List[Item] 时,预计您也可以写入Items。因此,您可以改用RootJsonFormat 并抛出异常以防您尝试编写它(因为您不支持它)。例如:

import spray.json._

implicit object TestJsonFormat extends RootJsonFormat[Test] 

  override def read(json: JsValue): Test = 

    val jsObject = json.asJsObject
    val jsFields = jsObject.fields

    val i = jsFields.get("i").map(_.convertTo[Int]).getOrElse(0)
    val d = jsFields.get("d").map(_.convertTo[Double]).getOrElse(0d)

    Test(i, d)
  

  override def write(obj: Test): JsValue = serializationError("not supported")

如果您知道仅涉及读者的干净解决方案,请告诉我,因为我自己遇到了这个问题并且找不到其他任何东西。

【讨论】:

感谢您的回答。我刚刚从github问题中学到了它。对于干净的解决方案,请检查我的答案,我认为它不是很干净,但我不想总是覆盖 write 方法,因为我们有很多自定义格式化程序,它的开销很大,所以我创建了一个基本特征来做到这一点。跨度> 我明白了 :) 我很久以前就遇到过这个问题,我有点习惯于重写(未使用的)写入方法。谢谢。【参考方案2】:

我了解到限制来自spray-json:

spray-json 的类型类基础结构是围绕 (Root)JsonFormat 类型构建的,而不是 (Root)JsonReader。因此,即使您只是在阅读,也确实必须提供“格式”。

Check here.

克服问题;我创建了另一个 trait 扩展了 RootJsonFormat 而不是 reader,并用基本上未实现的方法覆盖了 write 方法。

trait EmptyWriterFormat[T] extends RootJsonFormat[T] 
  override def write(o: T): JsValue = ???

【讨论】:

以上是关于spray-json 找不到 List[T] 类型的 JsonReader的主要内容,如果未能解决你的问题,请参考以下文章

Spray-json 用于 List 上的普通类(非大小写)

SerializationException:在 c# unity3d 中找不到类型'System.Collections.Generic.List`1

有问题,找不到类型或命名空间名称“List”

找不到类型或命名空间名称“T”(您是不是缺少 using 指令或程序集引用?)

C#实体类中如何定义泛型集合类型的属性

TS错误:“找不到名称'T'如何通过泛型?