2
votes

I've a case class similar to this found here :

case class WebCategory(topGroupName: String,
                       topGroupID: String,
                       webCategoryName : String,
                       webCategoryID : String,
                       subWebCats:Seq[SubWebCat])

case class SubWebCat(name:String, id:String)

And my request body json is having the exact same key names as of case class. For ex:

{
  "webCategoryID" : "blah",
  "webCategoryName" : "abcabc",
  "topGroupID" : "blah",
  "topGroupName" : "namehere",
  "subWebCats" : [
    {
      "name" : "blah",
      "id" : "idblah"
    },
            {
      "name" : "another blah",
      "id" : "another idblah"
    } 

  ]

}

The case class & req body keys are same then is it possible to directly build the case class object from request json? If it is possible then how can I do this? Any references would help. If it is not possible then this means I've to define my custom implicit converter explained in the answer in which I don't have any problem implementing it.

Note: I'm using Play 2.3 & Scala 11 for my development

2

2 Answers

9
votes

You can use Play's built-in JSON validation for this quite easily. You don't need to add any third-party dependencies for this.

case class WebCategory(topGroupName: String,
                       topGroupID: String,
                       webCategoryName : String,
                       webCategoryID : String,
                       subWebCats:Seq[SubWebCat])

object WebCategory {
  implicit val fmt = Json.format[WebCategory]
}

case class SubWebCat(name:String, id:String)

object SubWebCat {
  implicit val fmt = Json.format[SubWebCat]
}

Then, in your controller action:

def save: Action(parse.json) { implicit request =>
  request.body.validate[WebCategory].fold(
    errors => BadRequest(errors.mkString),
    category => Ok("saved category")
  )
}
1
votes

We use FasterXml for serialization and deserialization as follows.

include this dependency in your build.sbt

"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.4.0-rc2"

Create a two helper functions toJson and fromJson to serialize and deserialize

 object JsonProvider {
    
      //create mapper and register scala module
      private val mapper = new ObjectMapper
      mapper.registerModule(DefaultScalaModule)      
    
      def toJson(obj: Object): String = {
        val writer = new StringWriter
        mapper.writeValue(writer, obj)
        writer.toString
      }
    
      def fromJson[T: scala.reflect.Manifest](json: String): T = {
        mapper.readValue(json, scala.reflect.classTag[T].runtimeClass).asInstanceOf[T]
      }
 }

Use it as follows to cast your request body into case class.

JsonProvider.fromJson[WebCategory](request.body.toString())

to convert caseclass to json use it like this.

JsonProvider.toJson(obj);

where "obj" is the object of case class.

Problem with Play-Json default.

Suppose you have case class A with three parameters as follows

case class A(id:String,name:String,roll:Int)

and if your Json you want to parse is as follows

{
name:"XYZ",
roll:22
}

you can't parse this Json with play-json because of the missing field or one way is to define your Read and write functions which is very cumbersome.

but with fasterXML you can easily parse this Json like :

val a = JsonProvider.fromJsonA

and you can assign Id to case class A later like val a1 = a.copy(id="xyz")

i had this problem then i switched from play-json to fasterXML the problem was How to send Json from client with missing fields for its corresponding Case Class after using Json.format function