Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

spray-json can't find JsonReader for type List[T]

I'm creating custom json readers for case classes but it can't find implicit JsonReader type class for List[T] which is used in other case class.

When I checked DefaultJsonProtocol, it has implicit format for collections already;

  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)
    }
  }

Here is the simplified code;

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)
    }
  }

}

Here is the errors;

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)
                                                ^
like image 524
Fatih Donmez Avatar asked May 25 '16 03:05

Fatih Donmez


1 Answers

I think the problem is related to the fact that the JsonReader for List[T] in DefaultJsonProtocol is a RootJsonFormat (not a RootJsonReader), which basically means you can read it and also write it. So, when you try to read a List[Item], it's expected that you are also able to write Items. So, you could use RootJsonFormat instead and throw an exception in case you try to write it (since you don't support it). For example:

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")
}

If you are aware of a clean solution involving only the readers, please do let me know because I ran into this problem myself and couldn't find anything else.

like image 140
ale64bit Avatar answered Sep 22 '22 10:09

ale64bit