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]

      

+3


source to share


1 answer


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)

      

+3


source







All Articles