What's the most elegant way to deconstruct a JSON array from JSON4?

I need to deconstruct the following JSON into a list of case classes:

{
  "data": [
    [49, true, 14, null, null],
    [52, false, null, null, null],
    [72, true, 4, 2, 1]
  ]
}

      

case class:

case class Data(i1: Int, b: Bool, i2: Option[Int], i3: Option[Int], i4: Option[Int])

      

I started with understanding but couldn't finish it:

for {
  JArray(data) <- json \ "data"
  JArray(d) <- data
  JInt(line) <- d.head // ???
} yield Data()

      

Any help is greatly appreciated.

Thank,

Michael

+3
json scala json4s


source to share


2 answers


You can write CustomSerializer

for Data

.

I introduced an extractor JOptionInt

to turn a JInt

or JNull

into Option[Int]

, maybe this can be done directly in json4s.

import org.json4s._
import org.json4s.jackson.JsonMethods._
import org.json4s.JsonDSL._

case class Data(i1: Int, b: Boolean, i2: Option[Int], i3: Option[Int], i4: Option[Int])

object DataSerializer extends CustomSerializer[Data]( format => ( 
  {
    case JArray(List(JInt(i1), JBool(b), JOptionInt(i2), JOptionInt(i3), JOptionInt(i4))) =>
      Data(i1.toInt, b, i2, i3 , i4) 
  }, {
    case d: Data => JArray(List(d.i1, d.b, d.i2, d.i3, d.i4)) 
  }  
))

object JOptionInt {
  def unapply(x: JValue) : Option[Option[Int]] = x match {
    case JInt(i) => Option(Option(i.toInt))
    case JNull   => Option(None)
    case _       => None
  }
}

      



which can be used like:

implicit val formats = DataSerializer

val json = parse("""
      {
        "data": [
          [49, true, 14, null, null],
          [52, false, null, null, null],
          [72, true, 4, 2, 1]
        ]
      }
      """)

val result = (json \ "data").extract[Array[Data]]
// Array(Data(49,true,Some(14),None,None), Data(52,false,None,None,None), Data(72,true,Some(4),Some(2),Some(1)))

      

+2


source to share


If you can allow the Rapture JSON library to be included, it can be done as follows, while still using the JSON4S backend. This requires the following imports:

import rapture.json._, jsonBackends.json4s._

      

If you already have JSON as JValue

, you can convert it to Rapture type Json

like this:

val json = Json(jValue)

      



Given your case class definition, you need to override the JSON extractor for types Data

(there is already a default extractor that expects a JSON object), e.g .:

implicit val dataExtractor = Json.extractor[Json].map { j =>
  Data(j(0).as[Int], j(1).as[Boolean], j(2).as[Option[Int]],
      j(3).as[Option[Int]], j(4).as[Option[Int]])
}

      

and you can extract it with:

val list = json.as[List[Data]]

      

+4


source to share







All Articles
Loading...
X
Show
Funny
Dev
Pics