Search code examples
scalaspray-json

Spray JSON Format and Conversion Error


I have a trait for which I wanted to write Typeclasses for. This trait actually is a contract to do JSON to Case class conversion and vice versa. The definition of the trait is as below:

trait Converter[T] {
    def convertFromJson(msg: String): Either[ConverterError, T]
    def convertToJson(msg: T): String
}

Now, for one of the case classes that I have, I have defined the implementation like this:

object Converter extends DefaultJsonProtocol {

        implicit object DefaultMessageConversions extends Converter[DefaultMessage] {
            implicit val json = jsonFormat(DefaultMessage, "timestamp")

            def convertFromJson(msg: String): Either[ConverterError, DefaultMessage] = {
                try {
                    Right(msg.parseJson.convertTo[DefaultMessage])
                }
                catch {
                    case _: Exception => Left(ConverterError("Shit happens"))
                }
            }
            def convertToJson(msg: DefaultMessage) = {
                implicit val writes = Json.writes[DefaultMessage]
                Json.toJson(msg).toString
            }
        }

        def apply[T: Converter] : Converter[T] = implicitly
    }

But I run into some compiler errors when I tried to build my project. I'm not sure what I did wrong?

[error] /Users/joesan/ingestion/src/main/scala/com/my/project/common/JsonMessageConversion.scala:28: could not find implicit value for evidence parameter of type com.my.project.common.JsonMessageConversion.Converter.JF[org.joda.time.DateTime]
[error]             implicit val json = jsonFormat(DefaultMessage, "timestamp")

Here is how my case class look like:

  case class DefaultMessage(timestamp: DateTime) extends KafkaMessage {
    def this() = this(DateTime.now(DateTimeZone.UTC))
  }

Solution

  • Your DefaultMessage uses org.joda.time.DateTime and spray-json does not know how to serialize/deserialize it out of the box.

    Therefore you need to define a RootJsonFormat[DateTime] and bring it in implicit scope.

    Here is an example implementation.