Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
643 views
in Technique[技术] by (71.8m points)

scala - Iterating over an array in JSON with Play 2.1.1

I am using play 2.1.1 and I am having issues iterating through an array. I had read somewhere that you can create a reads for a List[Object] but everytime I try to do this I get an error "No unapply function found" for the line that says

implicit val userListReads: Reads[List[FBUser]] = Json.reads[List[FBUser]]". The issue is " = Json.reads[List[FBUser]]

I am at a loss of what else to try. Any assistance would be greatly appreciated.

def linkUsers() = Action { implicit request =>
  val json = Json.parse("{"data": [{"name": "Me Lazyan","id": "1182"},{"name": "Chales Dselle","id": "10115"},{"name": "Be My","id": "10275"},{"name": "De Rwani", "id": "11189"},{"name": "Phoe Johon", "id": "11372"}]}")

  val peoples = json.validate[List[FBUser]].get
  peoples.foreach(println)

  Ok(json).withHeaders(CONTENT_TYPE -> "text/json")
}

case class FBUser(
  name: String,
  id: String 
)

object FBUser {
    /** Uses a Scala Macro to define the Reads function */
    implicit val userReads: Reads[FBUser] = Json.reads[FBUser]
    implicit val userListReads: Reads[List[FBUser]] = Json.reads[List[FBUser]]
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Purpose

Even if the the @martin's answer is giving the straight solution regarding the mismatch between the json message and the expected result, I'd like to give you some advices for a clean way to reach your goal.

That's because, AFAICK, you're redefining way too much things and you could meet cases where errors aren't reported... but just hidden by a different error like NoSuchElementException.

Lastly, I would like to give a solution where your message is kept unchanged (like the second @Martin 's solution was).

Proposition

The idea is to keep things packaged with their responsibilities also the code is split in three different files:

FBUser.scala which simply declares the model structure

package models

case class FBUser(
    name: String,
    id: String
)

formats.scala which is a package that will gather all formats definition, specially the json ones:

package models

import play.api.libs.json._
import play.api.libs.json.Reads._
import play.api.libs.json.util._
import play.api.libs.json.Json._
import play.api.libs.functional.syntax._

package formats {

  object jsons {
    implicit val fbUserFormat:Format[FBUser] = Json.format[FBUser]
  }

}

Note that the format for List[FBUser] is not provided because the json api will resolve to the implicit and generic Reads and OWrites.

And lastly, the Application.scala that will contain code only relevant to some use cases, like the json object containing a data field, the list of FBUser.

package controllers

import play.api._
import play.api.mvc._
import play.api.libs.json._
import play.api.libs.json.Json._

import models._

object Application extends Controller {

  import models.formats.jsons._
  val readUserFromInput = (__  'data).read[List[FBUser]]

  def index = Action {
    val jsonString = "{"data": [{"name": "Me Lazyan","id": "1182"},{"name": "Chales Dselle","id": "10115"},{"name": "Be My","id": "10275"},{"name": "De Rwani", "id": "11189"},{"name": "Phoe Johon", "id": "11372"}]}"

    val json = Json.parse(jsonString)
    val users = json.validate(readUserFromInput)

    users.map(
      list => Ok(Json.toJson(list)) // or Ok(json) to match exactly you example
    ).recoverTotal{
      err => BadRequest(JsError.toFlatJson(err))
    }
  }

}

In this controller, we can see that it defines the specific Reads for the initial case, thus the access to the data field and the reads to FBUser instance are safe thanks to the use of validate, map and recoverTotal.

Some words

A last note about safety, Json.parse is not safe so in order to be even more safe you should consider some options depending on your workflows, some of them are: * using the json body parser that'll let you handle bad json format explicitly * using a dedicated case class defined in the controller for this particular case (and then define its Reads/... using inception like for FBUser)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...