BitPusher
BitPusher

Reputation: 1030

spray-json - diverging implicit expansion

I'm attempting to interface with the RescueTime API via spray-json. Results are of the form:

{
"notes":"data is an array of arrays (rows), column names for rows in row_headers",
"row_headers":[
  "Rank",
  "Time Spent (seconds)",
  "Number of People",
  "Activity",
  "Category",
  "Productivity"
],
"rows":[
  [
     1,
     16611,
     1,
     "iTerm",
     "Systems Operations",
     2
  ]
]
}

As of yet, I'm attempting to hash out the right case classes. Here's what I've got so far:

package test

import spray.json._

case class RescueTimeApiResult(notes: String, row_headers: List[String], rows: List[List[Either[Int, String]]])

object MyJsonProtocol extends DefaultJsonProtocol {
  implicit def rescueTimeApiResultFormat[T: JsonFormat]  = jsonFormat3(RescueTimeApiResult)
}

private object Tester extends App {
  val notes = "data is an array of arrays (rows), column names for rows in row_headers"
  val headers = List("Rank", "Time Spent (seconds)", "Number of People", "Activity", "Category", "Productivity")

  val entry1 = List(wrapInt(1),
                wrapInt(16611),
                wrapInt(1),
                wrapString("iTerm"),
                wrapString("Systems Operations"),
                wrapInt(2))

  def wrapInt(x: Int): Either[Int, String] = Left(x)
  def wrapString(s: String): Either[Int, String] = Right(s)

  val rows = List(entry1)

  val obj = RescueTimeApiResult(notes, headers, rows)
  println(obj)

  import MyJsonProtocol._
  println(obj.toJson)
}

This is all well and good, but at compile time scalac yields:

Error:(31, 15) diverging implicit expansion for type spray.json.JsonWriter[test.RescueTimeApiResult]
starting with method rescueTimeApiResultFormat in object MyJsonProtocol
  println(obj.toJson)
          ^

My understanding of diverging implicit expansion is rough at best. Roughly, there is a cycle in implicit search. As I understand, the toJson implicit comes from the spray.json._ import which expects a JsonWriter implicit parameter. This, in turn, is provided by the MyJsonProtocol object. However, why this particular implicit parameter introduces a cycle is beyond me. One theory is toJson conversion which applies to Any might be interfering with the implicit parameter resolution, but that's just a hunch.

Any help is greatly appreciated.

Upvotes: 1

Views: 476

Answers (1)

BitPusher
BitPusher

Reputation: 1030

I found a solution, though I'm still very interested in a general explanation.

Essentially, I reduced the problem to the implicit definition of the MyJsonProtocol. It occurred to me there wasn't much utility in deferring evaluation by declaring the implicit parameter as a def as opposed to a val. Furthermore, in removing the type parameter, as my use case is rather concrete, I was able to get around the whole diverging implicit expansion bit.

Upvotes: 1

Related Questions