Robert Simmons Jr.
Robert Simmons Jr.

Reputation: 1182

How to define a JSON format for an object with nested generic types?

I have a case class with this definition:

case class EndpointResponse[A](timestamp: Instant, uuid: UUID, content: A)

and

case class User(id: UUID, username: String, email: String)

And a JsonFormat with the following definition:

trait EndpointsJsonProtocol extends DefaultJsonProtocol {

  implicit def endpointResponseJsonFormat[A: JsonFormat] = new RootJsonFormat[EndpointResponse[A]] {
    val dtFormatter = DateTimeFormatter.ISO_INSTANT

    override def write(response: EndpointResponse[A]): JsValue = response match {
      case _: EndpointResponse[_] => JsObject(
        "timestamp" -> JsString(dtFormatter.format(response.timestamp)),
        "uuid" -> JsString(response.uuid.toString), // note we don't encode to slug on purpose
        "content" -> response.content.toJson
      )
      case x => deserializationError("Deserialization not supported " + x)
    }

    override def read(value: JsValue): EndpointResponse[A] = value match {
      case JsObject(encoded) =>
        value.asJsObject.getFields("timestamp", "uuid", "content") match {
          case Seq(JsString(timestamp), JsString(uuid), content) =>
            EndpointResponse(Instant.from(dtFormatter.parse(timestamp)), UUID.fromString(uuid), content.convertTo[A])
          case x => deserializationError("Unable to deserialize from " + x)
        }
      case x => deserializationError("Unable to deserialize from " + x)
    }
  }

  implicit def userResponseFormat: JsonFormat[User] = jsonFormat3(User.apply)
}

/** Singleton of the JsonProtocol */ object EndpointsJsonProtocol extends EndpointsJsonProtocol

Now when I try to convert to json with a simple type as content it works fine.

EndpointResponse(uuid, user).toJson

But when I try it with a nested generic it wont compile.

val records: List[User] = // not relevant
EndpointResponse(uuid, records).toJson

Any idea what I am doing wrong here? Thanks in advance. I have imported the spray.json._ and the my custom protocol so that isn't the issue.

Edit: I wasn't importing the protocol but a class with a similar name. Welcome to programming! :) At least someone maybe can benefit from this.

Upvotes: 3

Views: 618

Answers (1)

Robert Simmons Jr.
Robert Simmons Jr.

Reputation: 1182

Silly Me, I had imported the wrong type. Once I imported the right type, this works. Hope the code helps someone else.

Upvotes: 1

Related Questions