Search code examples
jsonscalaplay-json

Json object to map


Hello I would like to transform json object into map using implicit Reads. With the code below I run into a StackOverflow error, any one could see what the problem is :

"pass": {
  "key-1": {
    "field1": "aaaa",
    "field2": "aaaa"
  },
  "key-2": {
    "field1": "aaaa",
    "field2": "aaaa"
  },
  "key-3": {
    "field1": "aaaa",
    "field2": "aaaa"
  }
}

case class Pass(field1: String, field2: String)

implicit val mapReads: Reads[Map[String, Pass]] = new Reads[Map[String, Pass]] {
  def reads(jv: JsValue): JsResult[Map[String, Pass]] =
    JsSuccess(jv.as[Map[String, Pass]].map{
      case (k, v) => k -> v.asInstanceOf[Pass]
    })
}

val passMap = (json \ "pass").validate[Map[String, Pass]]

Here is the stack error :

java.lang.StackOverflowError
  at play.api.libs.json.JsReadable$class.as(JsReadable.scala:23)
  at play.api.libs.json.JsObject.as(JsValue.scala:124)
  at com.MyHelper$$anon$1.reads(MyHelper.scala:51)
  at play.api.libs.json.Format$$anon$3.reads(Format.scala:65)
  at play.api.libs.json.JsValue$class.validate(JsValue.scala:17)
  at play.api.libs.json.JsObject.validate(JsValue.scala:124)
  at play.api.libs.json.JsReadable$class.as(JsReadable.scala:23)
  at play.api.libs.json.JsObject.as(JsValue.scala:124)

Solution

  • Maybe you will be more likely to create a MapPass class case and use Json.format to do the work for you!

    import play.api.libs.json._
    
    val a: String = """{
      "pass": {
        "key-1": {
        "field1": "aaaa",
        "field2": "aaaa"
      },
        "key-2": {
        "field1": "aaaa",
        "field2": "aaaa"
      },
        "key-3": {
        "field1": "aaaa",
        "field2": "aaaa"
      }
      }
    }"""
    
    case class Pass(field1: String, field2: String)
    
    case class MapPass(pass: Map[String, Pass])
    
    implicit val passFormat: Format[Pass] = Json.format[Pass]
    implicit val mapPassFormat: Format[MapPass] = Json.format[MapPass]
    
    val json = Json.parse(a)
    val mapPassJsResult = json.validate[MapPass]
    val mapPass = mapPassJsResult.get
    print(mapPass.pass.mkString("\n"))
    

    It worked like that for me:

    enter image description here