Play 2.3 with Scala, converting JSON array to sequence
Welcome,
I really wanted to avoid it, but now I give up. I am trying to loop through a json array and output some elements and put them in order. I tried many options, tried everything from game docs, many tries and still have the same error: null pointer exception when my method tries to delete elements. Therefore my json example:
[
{
"var1": "xx",
"var2": "xxx",
"var3": 111
},
{
"var1": "yy",
"var2": "yyy",
"var3": 222
},
{
"var1": "zz",
"var2": "zzz",
"var3": 333
}
]
I've defined a lot of Reads configurations, the last one like that, but doesn't even want to compile; /
case class Vars1(vars: Seq[String])
val var1Reads: Reads[String] = (__ \ "var1").read[String]
implicit val vars1Reads: Reads[Vars1] = ((__).read[Seq[String]])(Vars1.apply _)
I want to create Sequence or List, it doesn't matter, only from var1 from each element of this array. It can be a pure sequence, or a case class with a sequence or something else. Simple how to iterate through json arrays? I've tried many configurations, reading var1 is not problematic, but when I want to read all vars 1 from every element of the array, then I have a null pointer exception. Please can anyone point me in a good direction, give me a hint, what am I doing wrong? Please don't blame, I am new to programming and I started learning scala and playing frameworks.
Thanks for any help.
Update:
I tried this too:
implicit val vars1Reads = (__).read(Reads.list((__).read[String])).map( var => Vars(var))
but still i got the same error:
[NoSuchElementException: JsError.get]
source to share
The simplest way of parsing is to allow the parsing of the array body to be reproduced as Seq[_]
, that is, a sequence of objects.
I would suggest that every element in your array should be represented by a case class, eg.
case class Var1(var1: String)
This provides a useful type with which you can add validation for input from JSON.
You can add implicit Reads
at the appropriate place like
object Var1 {
implicit val var1Reads: Reads[Var1] = {
((__ \ "var1").read[String]).map(Var1.apply _)
}
}
Note that read / write macros have a limitation if they don't work in a documented way when the case class has a single field - see http://grokbase.com/t/gg/play-framework/131bx7pcyd/play2-1-scala -json-writing-a-reads-writes-for-a-single-field-case-class
- This is why the call was added map
. The macro should work as documented if there are 2 or more fields.
Then you can use this to create Seq [Var1] like
def test = Action(BodyParsers.parse.json) { request =>
val result = request.body.validate[Seq[Var1]]
...
}
And the result (here I just print out the value of result.toString):
$ curl --include --request POST --header "Content-type: application/json" --data '[{"var1": "3", "var2": "4"}, {"var1": "7"}]' http://localhost:9000/test
HTTP/1.1 200 OK
Content-Type: text/plain; charset=utf-8
Content-Length: 34
JsSuccess(List(Var1(3), Var1(7)),)
Update
As mentioned in the comments below, you can simplify your implementation Reads[Var1]
by using a macro like this:
implicit val var1Reads = Json.reads[Var1]
This will only do what you want if the field is called var1
, i.e.
case class Var1(var1: String)
source to share