2013-12-11 2 views
6

Я новичок в API Spray-Json, и я пытаюсь разобрать ответ Json от Docker REST API.Spray-Json: Как разобрать Json Array?

There является чистым примером использования Spray-Json разобрать этот ответ Google Map JSon:

{ 
    "results" : [ 
     { 
     "elevation" : 8815.7158203125, 
     "location" : { 
      "lat" : 27.988056, 
      "lng" : 86.92527800000001 
     }, 
     "resolution" : 152.7032318115234 
     } 
    ], 
    "status" : "OK" 
} 

В приведенном выше примере внешний уровень является Object. Тем не менее, мне нужно непосредственно разобрать ответ JSON, чей внешний уровень представляет собой Array, состоящие из информации контейнеров, как показано ниже:

[ 
    { 
     "Id": "8dfafdbc3a40", 
     "Image": "base:latest", 
     "Command": "echo 1", 
     "Created": 1367854155, 
     "Status": "Exit 0", 
     "Ports":[{"PrivatePort": 2222, "PublicPort": 3333, "Type": "tcp"}], 
     "SizeRw":12288, 
     "SizeRootFs":0 
    }, 
    { ... }, 
    { ... } 
] 

Вот код, который я адаптировано из примера карты Google:

package main 

import ... 

case class Container(id: String, image: String, command: String, created: Long, status: String, ports: List[Port], sizeRW: Long, sizeRootFs: Long) 
case class Port(privatePort: Long, publicPort: Long, portType: String) 
case class DockerApiResult[T](results: List[T]) 

object ContainerListJsonProtocol extends DefaultJsonProtocol { 
    implicit val portFormat = jsonFormat3(Port) 
    implicit val containerFormat = jsonFormat8(Container) 
    implicit def dockerApiResultFormat[T :JsonFormat] = jsonFormat1(DockerApiResult.apply[T]) 
} 

object Main extends App { 

    implicit val system = ActorSystem("simple-spray-client") 
    import system.dispatcher // execution context for futures below 
    val log = Logging(system, getClass) 

    log.info("Requesting containers info...") 

    import ContainerListJsonProtocol._ 
    import SprayJsonSupport._ 
    val pipeline = sendReceive ~> unmarshal[DockerApiResult[Container]] 

    val responseFuture = pipeline { 
    Get("http://<ip-address>:4243/containers/json") 
    } 

    responseFuture onComplete { 
    case Success(DockerApiResult(Container(_,_,_,_,_,_,_,_) :: _)) => 
     log.info("Id of the found image: {} ") 
     shutdown() 

    case Success(somethingUnexpected) => 
     log.warning("The Docker API call was successful but returned something unexpected: '{}'.", somethingUnexpected) 
     shutdown() 

    case Failure(error) => 
     log.error(error, "Couldn't get containers information") 
     shutdown() 
    } 

    def shutdown(): Unit = { 
    IO(Http).ask(Http.CloseAll)(1.second).await 
    system.shutdown() 
    } 
} 

И ниже исключение я получаю (Object expected):

spray.httpx.PipelineException: MalformedContent(Object expected,Some(spray.json.DeserializationException: Object expected)) 

Я, конечно, пропустить что-то очевидное, но Как разобрать Json Array с помощью Spray-Json?

Кроме того, есть ли простой способ сделать это, не имея дело с пользовательским JsonFormat или RootJsonFormat?

+0

Лично я бы переключился на Lift-json :) –

ответ

13

Делая unmarshal[DockerApiResult[Container]], вы говорите распылительную JSON, что вы ожидаете формат быть JSON объект формы:

{ results: [...] } 

так case class DockerApiResult[T](results: List[T]) определяется как объект с одним полем результатов содержащей список.

Вместо этого вам нужно сделать:

unmarshal[List[Container]] 

, а затем работать на результирующем списке непосредственно (или обернуть его в DockerApiResult после того, как он был разобран распылением JSON).

Если вы хотите спрей JSON для распаковать непосредственно в DockerApiResult, вы можете написать JsonFormat что-то вроде:

implicit object DockerApiResultFormat extends RootJsonFormat[DockerApiResult] { 
    def read(value: JsValue) = DockerApiResult(value.convertTo[List[Container]]) 
    def write(obj: DockerApiResult) = obj.results.toJson 
} 
+0

Спасибо! Это сработало. Я действительно пытался с помощью 'unmarshal [List [Container]]', но я смутился с атрибутом Port, который был null, и мне пришлось обернуть его «Option». В любом случае отличный ответ, именно то, что я искал;) – abronan

6

боролись с этим немного и нашел способ преобразовать в JsArray из JSON разобранной строка с использованием спрея:

import spray.json._ //parseJson 
val kkkk = 
    """ 
    |[{"a": "1"}, {"b": "2"}] 
    """.stripMargin.parseJson.asInstanceOf[JsArray] 
Смежные вопросы