Parsing a simple array with Spray-json

pogo picture pogo · Feb 15, 2015 · Viewed 8.4k times · Source

I'm trying (and failing) to get my head around how spray-json converts json feeds into objects. If I have a simple key -> value json feed then it seems to work ok but the data I want to read comes in a list like this:

[{
    "name": "John",
    "age": "30"
},
{
    "name": "Tom",
    "age": "25"
}]

And my code looks like this:

package jsontest

import spray.json._
import DefaultJsonProtocol._

object JsonFun {

  case class Person(name: String, age: String)
  case class FriendList(items: List[Person])

  object FriendsProtocol extends DefaultJsonProtocol {
    implicit val personFormat = jsonFormat2(Person)
    implicit val friendListFormat = jsonFormat1(FriendList)
  }

  def main(args: Array[String]): Unit = {

    import FriendsProtocol._

    val input = scala.io.Source.fromFile("test.json")("UTF-8").mkString.parseJson

    val friendList = input.convertTo[FriendList]

    println(friendList)
  }

}    

If I change my test file so it just has a single person not in an array and run val friendList = input.convertTo[Person] then it works and everything parses but as soon as I try and parse an array it fails with the error Object expected in field 'items'

Can anyone point me the direction of what I'm doing wrong?

Answer

pogo picture pogo · Feb 15, 2015

Well, as is often the way immediately after posting something to StackOverflow after spending hours trying to get something working, I've managed to get this to work.

The correct implementation of FriendsProtocol was:

object FriendsProtocol extends DefaultJsonProtocol {
  implicit val personFormat = jsonFormat2(Person)
  implicit object friendListJsonFormat extends RootJsonFormat[FriendList] {
    def read(value: JsValue) = FriendList(value.convertTo[List[Person]])
    def write(f: FriendList) = ???
  } 
}

Telling Spray how to read / write (just read in my case) the list object is enough to get it working.

Hope that helps someone else!