Search code examples
jsonscalaimplicit-conversionimplicitspray-json

Companion objects, implicits, and Json


I am having trouble adding an implicitly defined type converter for a type for which I also have a Json format. I doubt if the problem has anything to do with Json (or Spray). Or MyDate for that matter.

Here's a fragment of code which leads to the problem I'm experiencing:

case class MyDate(y: Int, m: Int, d: Int)
object JsonProblem extends App {
import spray.json.{DefaultJsonProtocol, _}
object MyJsonProtocol extends DefaultJsonProtocol with NullOptions {
  implicit val myDateFormat = jsonFormat3(MyDate)
}
import MyJsonProtocol._
val exampleDate = """{ "y": 2016, "m": 7, "d": 11 }"""
val y: MyDate = exampleDate.parseJson.convertTo[MyDate]
}

So far, everything works as expected. The value y takes on the appropriate instance of MyDate.

Now, after the case class definition (although I don't think it matters where I put this code), I introduce a companion object thus:

object MyDate {
  implicit def convertMyDateToInt(x: MyDate): Int = ???
}

Immediately, I get a compiler error on the myDateFormat line: *cannot resolve reference jsonFormat3 with such signature*. The purpose of my additional code is unrelated (from my point of view) to the Json parsing. It is because in some other part of the code I want to implicitly convert MyDate into Int.

I expect that it has to do with the fact that I am replacing (or enhancing) a compiler-generated companion object with my own. But what exactly is the problem and how can I work around it?


Solution

  • Just use the companion objects apply function

    import spray.json._
    
    case class MyDate(y: Int, m: Int, d: Int)
    
    object MyDate {
      implicit def convertMyDateToInt(x: MyDate): Int = ???
    }
    
    object JsonProblem extends App {
      object MyJsonProtocol extends DefaultJsonProtocol with NullOptions {
        implicit val myDateFormat:RootJsonFormat[MyDate] = jsonFormat3(MyDate.apply)
      }
      import MyJsonProtocol._
      val exampleDate = """{ "y": 2016, "m": 7, "d": 11 }"""
      val y: MyDate = exampleDate.parseJson.convertTo[MyDate]
    }