简体   繁体   中英

JSON Reads combinator in Play scala 2.x doesn't work for Map[String, _]

I have a Play-scala v2.3 application. Looking from this guide about Json Combinators , I'm trying to do this:

object Application extends Controller {

  case class Foo(id: String, docs: List[Map[String, _]])

  implicit val fooReads = (
    (JsPath \ "id").read[String] and
    (JsPath \ "docs").read[List[Map[String, _]]]
  )(Foo.apply _)

  ...
}

But then I got compile error:

No Json deserializer found for type List[Map[String, _]]. Try to implement an implicit Reads or Format for this type.
       (JsPath \ "docs").read[List[Map[String, _]]]
                             ^

This is the example json that need to be read:

{
    "id": "001",
    "docs": [
        {
            "name": "Billy",
            "level": 2,
            "marked": false
        },
        {
            "name": "Fred",
            "level": 5,
            "marked": true
        }
    ]
}

I also have tried this:

  case class Foo(id: String, docs: Map[String, _])

  implicit val fooReads = (
    (JsPath \ "id").read[String] and
    (JsPath \ "docs").read[Map[String, _]]
  )(Foo.apply _)

Same error too.

It seems Play's JSON combinator doesn't work for Map type. Anyone know how to solve this?

You'd be a lot better off avoiding Map[String, Any] , and Scala and Play make this easy. A much better solution is to define a custom case class for the thing you're trying to represent as a map:

import play.api.libs.json._

case class Doc(name: String, level: Int, marked: Boolean)
case class Foo(id: String, docs: List[Doc])

implicit val docFormat = Json.format[Doc]
implicit val fooFormat = Json.format[Foo]

val json = Json.parse(...)

And then:

scala> json.as[Foo]
res0: Foo = Foo(001,List(Doc(Billy,2,false), Doc(Fred,5,true)))

Or if you want more control:

import play.api.libs.functional.syntax._
import play.api.libs.json._

implicit val fooReads: Reads[Foo] = (
  (__ \ 'id).read[String] and
  (__ \ 'docs).read(
    Reads.list((
      (__ \ 'name).read[String] and
      (__ \ 'level).read[Int] and
      (__ \ 'marked).read[Boolean]
    )(Doc.apply _))
  )
)(Foo.apply _)

If you really need a Map[String, Any] , you can always write a conversion method on Doc .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM