Search code examples
scalaplayframeworkplayframework-2.6play-json

Building Reads converter and case class at runtime in Play Framework


I have a file that contains the following array of JSON objects:

[
    {
      "type": "home",
      "number": 1111
    },
    {
      "type": "office",
      "number": 2222
    },
    {
      "type": "mobile",
      "number": 3333
    }
  ]

In Play Framework 2.x I would define an implicit Reads converter to read the file and convert it to a Scala structure:

implicit val implicitRead : Reads[MyClass] = (
      (JsPath \ "type").read[String] and
      (JsPath \ "number").read[Int]
)  (MyClass.apply _)

the Scala case class defined as:

case class MyClass (myType: String, myNumber: Int)

and parsing the JSON with:

val json = // file record content    
json.validate[MyClass] match {
  case s: JsSuccess[MyClass] => {
    val myObject: MyClass = s.get
    // do something with myObject
  }
  case e: JsError => {
    // error handling flow
  }

Now, my problem is that I know the structure of the JSON file only at runtime, not at compilation time. Is it possible to build both the implicit Reads converter and the case class at runtime?


Solution

  • Use case classes directly with play-json:

    Change the case class to:

    case class MyClass (`type`: String, number: Int)
    

    Add the json-formatter to the companion object:

    object MyClass {
      implicit val format = Json.format[MyClass]
    }
    

    The validate function looks now:

    val myClass = // file record content    
    json.validate[Seq[MyClass]] match {
      case JsSuccess(myClasses, _) => myClasses
      case e: JsError =>  // handle error case
    }
    

    That's all you need. If you are not happy with the parameter names, you can use a Wrapper case class.