imagio
imagio

Reputation: 1490

Writes for JSON views with more than 21 fields in Play 2.3

I am writing a Play 2.3 application backed by mongodb which serves JSON to an angularjs client. The app is being ported from Rails and many of my existing mongo documents have more than 22 fields which prevented the use of Json.format macro to serialize them to/from case classes. I worked around that using shapeless from this gist (which I don't fully understand yet).

Now I am facing the problem of writing JSON "views" for the client. Not all of the data in my documents should be sent to the client -- hashed passwords and such. To send the correct data I am attempting to use a custom Writes but am running into the 21 field limit problem again. For example the following fails to compile:

val viewWrites: Writes[User] = (
(__ \ "id").write[String] and
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String] and 
(__ \ "u").write[String]
) { user: User =>
  (user._id.toString(),
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username,
    user.username)
}

with the error

play.api.libs.functional.FunctionalBuilder[play.api.libs.json.OWrites]#CanBuild22[String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String,String] does not take parameters

If I remove one of those fields it will compile correctly. I realize that I could break the model down into several parts but I don't want to do that because:

  1. I am porting this app from Ruby on Rails and the client already expects data in a particular format. I was using JBuilder on rails to make JSON views. I would rather not have to modify the client.
  2. There are lots of cases where writing JSON with more than 21 fields is required. I does not make sense that the play framework would just ignore those use cases. I feel I must be missing a common solution.

How can I write arbitrarily sized JSON "views" to serve my exiting client in the format that it expects?

Upvotes: 1

Views: 773

Answers (1)

ffxtian
ffxtian

Reputation: 559

declare your writes as follows:

implicit val viewWrites = new Writes[User] {
  def writes(user: User) = Json.obj(
    "id" -> user._id.toString(),
    "u" -> user.username,
    //repeat 20 times
    "u" -> user.username)
}

Basically, you're manually creating the Writes[User] object, and explicitly defining a writes method that takes a single parameter of type User, and returns a JsObject. You can include/exclude fields as needed.

Upvotes: 1

Related Questions