Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Play Scala No Json deserializer found for type (String, String). Try to implement an implicit Reads or Format for this type

These Json serializers in Play with Scala are driving me nuts.

I have read dozens of posts and the tutorials and the documentation. Tried four different ways of implementing Reads / Writes / Format overrides and all to no avail.

So I backed off the custom type and decided to go uber simple:

  def suggest = Action(parse.json) {
    request =>
      request.body.validate[(String, String)].map {
        case (suggestion, categories) => Ok("You suggested " + suggestion + " for categories " + categories)
      }.recoverTotal {
        e => BadRequest(JsError.toFlatJson(e))
      }
  }

And the error comes back as noted in the subject.

Do I really need to provide a custom Reads / Writes / Format implementation for such a basic body?

A sample input body could be:

{"suggestion":"add generics", "categories":"request;language;updates"}

What simple thing am I missing?

like image 204
Steve Wagner Avatar asked Apr 24 '13 05:04

Steve Wagner


2 Answers

Play! gives you a LOT of ways to work with Json. From the looks of your code, you're going down the Tuple road. Which essentially lets you convert Json into a Tuple. You're also using 'reads' which has the downside that you don't get precise error reporting (ie: if invalid json was passed you would know its invalid... but you wouldn't necessarily know why it was invalid). If you wanted more error handling then you need to start using the 'validate' method (details here: http://www.playframework.com/documentation/2.1.1/ScalaJsonCombinators).

Another way you could go is to map Json to case classes doing something like:

import play.api.libs.json._

case class MyClass(
  suggestion: String,
  categories: String
)

object MyClass {
  implicit val readsMyClass: Reads[MyClass] = new Reads[MyClass] {
    def reads(json: JsValue): JsResult[MyClass] = {
      for {
        suggestion <- (json \ "suggestion").validate[String]
        categories <- (json \ "categories").validate[String]
      } yield MyClass(json,categories)
    }
  }
}

This seems like a lot of code so Play 2.1 introduced Json 'Inception' which I have yet to try (http://www.playframework.com/documentation/2.1.1/ScalaJsonInception).

Finally, if you want the Json validation but don't necessary need to marshall/unmarshall case classes, then you can try the 'coast-to-coast' method. This will keep all your json as JsObject types but still give you validation. Sample code here: https://github.com/mandubian/play2-json-demo/blob/master/json-coast-to-coast/app/controllers/Application.scala

Hope this helps.

like image 125
sthomps Avatar answered Oct 26 '22 16:10

sthomps


So I added this:

  implicit val rds = (
    (__ \ 'suggestion).read[String] and
    (__ \ 'categories).read[String]
  ) tupled

And that seems to work.

Curious, though, is this really the best way to do this? It seems like a LOT of code if you have many many types to serialize / deserialize.

like image 36
Steve Wagner Avatar answered Oct 26 '22 16:10

Steve Wagner