1

I'm working with Play JSON API (latest version; Play 2.4), reading incoming JSON into objects.

When writing JSON, there's absolutely no problem in using a list of custom objects, as long as I have implicit val writes = Json.writes[CustomType].

But apparently the inverse is not true, as the following does not work even though Reads is generated for both top-level type and list item type (using Json.reads[Incoming] and Json.reads[Item]). Is custom Reads implementation mandatory? Or am I missing something obvious? What is the simplest way to make this work?

Simplified example:

JSON:

{
  "test": "...",
  "items": [
     { "id": 44, "time": "2015-11-20T11:04:03.544" },
     { "id": 45, "time": "2015-11-20T11:10:10.101" }
  ]
}

Models/DTOs matching the incoming data:

import play.api.libs.json.Json

case class Incoming(test: String, items: List[Item])

object Incoming {
  implicit val reads = Json.reads[Incoming]
}


case class Item(id: Long, time: String)

object Item {
  implicit val reads = Json.reads[Item]
}

Controller:

def test() = Action(parse.json) { request =>
  request.body.validate[Incoming].map(incoming => {
     // ... handle valid incoming data ...
  }).getOrElse(BadRequest)
}

Compiler has this to say:

No implicit format for List[models.Item] available.
[error]   implicit val reads = Json.reads[Incoming]
                       ^
No Json deserializer found for type models.Incoming. 
Try to implement an implicit Reads or Format for this type.
[error]     request.body.validate[Incoming].map(incoming => {

2 Answers 2

3

Try defining the case class and object for Item before those for Incoming. See this answer for more info: https://stackoverflow.com/a/15705581

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this works too! So, both of the answers, independently, fix the problem. I think I'll prefer this one (to the import tweak), because this is less likely to break again accidentally (e.g. via having "Optimize imports" enabled while committing).
1

The issue may be in your imports in Controller. Just importing "Incoming" will import the case class. In order to import the implicit val try "Incoming._". That will import all members of the Object Incoming.

2 Comments

Wow, you are right. It started working with these imports: import models.Incoming; import models.Incoming._; import models.Item._ So far I had trusted IntelliJ IDEA to handle and optimise imports for me, but in this case it failed.
It will never be able to know which implicit variable to use because it could come from many different places, this will always have to be manual.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.