Search code examples
jsonscalaplayframeworkplayframework-2.2

Making a model being able to convert itself to JSON


I run through the JSON documentation at http://www.playframework.com/documentation/2.2.x/ScalaJsonRequests but didn't find what I needed. What I need is make my class being able to be converted to JSON like this:

# model
case class MyClass(a: Int, b: String ....)

# controller

def myAction = Action {
  val myClass = getMyClass()
  Ok(toJson(myClass))
}

So wherever I call Ok(toJson(myClass)), it converts to JSON by itself. How can I do this?

P.S. Sorry, I forgot to mention MyClass has java.util.UUID as an Id and some other class as a field:

case class MyClass(id: UUID, a: Int, b: String, c: MyClass2 ....)

So Json.writes[MyClass] doesn't work at least because of UUID.


Solution

  • You could add a macro-generated Writes[MyClass] to companion object of MyClass like this:

    object MyClass {
      implicit val myClassWrites = Json.writes[MyClass]
    }
    

    Method toJson implicitly accepts parameter of type Writes[T]. Compiler tries to find such implicit value and companion object of MyClass is always in scope when type parameter T is MyClass, so you don't have to import myClassWrites manually.

    See also Where does Scala look for implicits?.

    Json.writes requires implicit Writes for all constructor parameters.

    case class MyClass(id: UUID, a: Int, b: String, c: MyClass2)
    

    If MyClass2 is a case class you should create Writes[MyClass2] using Json.writes in its companion object.

    For java.util.UUID you should create Writes manually, for instance:

    implicit val uuidWrites: Writes[UUID] = Writes{ uuid => JsString(uuid.toString) }
    

    You could create uuidWrites in some helper object and than import when you need it like this:

    object MyClass {
      import UuidHelper.uuidWrites 
      // note that you don't have to import MyClass2.myClass2Writes here
      implicit val myClassWrites = Json.writes[MyClass]
    }