3
votes

I'm trying to deserialize a json string into a generic collection.

My code looks something like this:

class MyClass(json: String) {
  def collectionType1: Set[Type1] = loadElements[Type1]

  def collectionType2: Set[Type2] = ???

  private def loadElements[T]: Set[T] = {
    json.parseJson.convertTo[Set[T]]
  }
}

I also have the following defined (I have the exact same definition for 'Type2', the case class looks different):

case class Type1(p1: String, p2: String)

object Type1JsonProtocol extends DefaultJsonProtocol {
  private implicit val collectionType1Format = jsonFormat2(Type1)

  implicit object Type1SetJsonReader extends JsonReader[Set[Type1]] {
    override def read(json: JsValue): Set[Type1] = json match {
      case JsArray(elements) => elements.map(_.convertTo[Type1]) toSet
      case x => deserializationError("Expected Collection as JsArray, but got " + x)
    }
  }
}

When compiling the code, I get the following error:

Error:(25, 29) Cannot find JsonReader or JsonFormat type class for Set[T]
    val res = json.convertTo[Set[T]]
                            ^

and:

Error:(25, 29) not enough arguments for method convertTo: (implicit evidence$1: spray.json.JsonReader[Set[T]])Set[T].
Unspecified value parameter evidence$1.
    val res = json.convertTo[Set[T]]
                            ^

I'm obviously missing something, but have a feeling it's something small. Does anyone have any clue?

Thanks!

1

1 Answers

2
votes

Following is the definition of convertTo function of JsValue.

def convertTo[T](implicit evidence$1 : spray.json.JsonReader[T])

As you can see, you should provide JsonReader for Type T as impilicit parameter.

You can't decide what is real type of T and its JsonReader, so simply use implicit param again like this:

private def loadElements[T: JsonReader]: Set[T]

If you not familiar with above style, you can expand that code like this:

private def loadElements[T](implicit p: JsonReader[T]): Set[T]

If you want to call this function, you should provide concrete type instead of type T and its JsonReader like this:

def collectionType1: Set[Type1] = {
  import Type1JsonProtocol.*
  loadElements[Type1]
}

You can detect wrong de/serialization problem at compile time instead of runtime by this technic.