Pradeep Saini
Pradeep Saini

Reputation: 71

value read is not a member of play.api.libs.json.JsValue

Was following Play Frameworks's Scala Json api Docs when got this error :

value read is not a member of play.api.libs.json.JsValue

My Imports are :

 import play.api.libs.json._       // JSON library
 import play.api.libs.json.Reads._ //custom validation helpers
 import play.api.libs.functional.syntax._   // Combinator syntax

and method throwing error is :

  def callSearchRoleRowInRoleService =  Action(parse.json) { 

  implicit request =>           

  var rolejson = request.body
  val roleId = (rolejson \ "roleId").read[Int]
  val shortDescription : Reads[String]= (rolejson \ "shortDescription").read[String]
  val description = (rolejson \ "description").read[String]    
  val activationDate = (rolejson \ "activationDate").read[java.sql.Date]
  val deactivationDate = (rolejson \ "deactivationDate").read[java.sql.Date]

  }

Working perfectly fine without read method

Upvotes: 0

Views: 2158

Answers (2)

Michael Zajac
Michael Zajac

Reputation: 55569

You really ought to deserialize your data to a case class. read[A] is a method on JsPath in order to create Reads[A] to combine into a larger Reads object. As @drexin mentioned, you're probably looking for as[A], however it is not a safe operation. If a single as fails, it throws an exception, which in your controller logic will result in a internal server error with little information to help the user.

You can construct Reads for a case class like this:

case class Role(id: Int, short: String, description: String, activation: java.sql.Date, deactivation: java.sql.Date)

object Role {
    implicit val reads: Reads[Role] = (
         (JsPath \ "roleId").read[Int] and 
         (JsPath \ "shortDescription").read[String] and 
         (JsPath \ "description").read[String] and 
         (JsPath \ "activationDate").read[java.sql.Date] and
         (JsPath \ "deactivationDate").read[java.sql.Date]
    )(Role.apply _)
}

Then your controller function would look more like this:

def callSearchRoleRowInRoleService =  Action(parse.json) { implicit request =>           
    request.body.validate[Role].fold(
        errors => { // handle validation errors, return some error message? },
        role => { // do something with the `role` to product a `Result` }
    )
}

The advantage of using validate is that all of the validation errors will be accumulated so they can be handled all at once, without throwing exceptions.

And because someone else is just bound to mention it, for simple case classes (like the one above), you can skip the combinators and use the macro:

 implicit val reads = Json.reads[Role]

Upvotes: 2

drexin
drexin

Reputation: 24423

You only have to use read[A] if you are using combinators to create a Reads[A]. The method you are looking for is as[A].

Upvotes: 1

Related Questions