Разбор простого массива с помощью Spray-JSON

Я пытаюсь (и не могу) понять, как спрей-json преобразует потоки json в объекты. Если у меня есть простой ключ -> значение json feed, то, похоже, он работает нормально, но данные, которые я хочу прочитать, появляются в виде списка:

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

И мой код выглядит так:

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)
  }

}    

Если я изменю свой тестовый файл так, чтобы в нем был только один человек, которого нет в массиве, val friendList = input.convertTo[Person] тогда это работает, и все анализирует, но как только я пытаюсь проанализировать массив, он завершается с ошибкой Object expected in field 'items'

Может кто-нибудь указать мне направление того, что я делаю неправильно?

2 ответа

Решение

Что ж, как это часто бывает сразу после публикации чего-либо в Stackru, потратив часы на то, чтобы заставить что-то работать, мне удалось заставить это работать.

Правильная реализация FriendsProtocol была:

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) = ???
  } 
}

Чтобы заставить Spray читать / писать (просто читать в моем случае) объект списка, достаточно, чтобы он заработал.

Надеюсь, что это помогает кому-то еще!

Чтобы упростить использование массива Friend, расширьте черту IndexedSeq[Person], реализовав соответствующие методы apply и leng th. Это позволит использовать стандартные методы API Scala Collections, такие как map, filter и sortBy, непосредственно в самом экземпляре FriendsArray без необходимости доступа к базовому значению Array[Person], которое он переносит.

case class Person(name: String, age: String)

// this case class allows special sequence trait in FriendArray class
// this will allow you to use .map .filter etc on FriendArray
case class FriendArray(items: Array[Person]) extends IndexedSeq[Person] {
    def apply(index: Int) = items(index)
    def length = items.length
}

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

import FriendsProtocol._

val input = jsonString.parseJson
val friends = input.convertTo[FriendArray]
friends.map(x => println(x.name))
println(friends.length)

Это тогда напечатает:

John
Tom
2
Другие вопросы по тегам