2013-11-19 4 views
3

Использование спрей-json (поскольку я использую распылитель-клиент), чтобы получить объект широты, долготы из API карт Google. Мне нужно создать всю структуру ответа:unmarshall inested json in spray-json

case class AddrComponent(long_name: String, short_name: String, types: List[String]) 
case class Location(lat: Double, lng: Double) 
case class ViewPort(northeast: Location, southwest: Location) 
case class Geometry(location: Location, location_type: String, viewport: ViewPort) 
case class EachResult(address_components: List[AddrComponent], 
         formatted_address: String, 
         geometry: Geometry, 
         types: List[String]) 
case class GoogleApiResult[T](status: String, results: List[T]) 

object AddressProtocol extends DefaultJsonProtocol { 
    implicit val addrFormat = jsonFormat3(AddrComponent) 
    implicit val locFormat = jsonFormat2(Location) 
    implicit val viewPortFormat = jsonFormat2(ViewPort) 
    implicit val geomFormat = jsonFormat3(Geometry) 
    implicit val eachResFormat = jsonFormat4(EachResult) 
    implicit def GoogleApiFormat[T: JsonFormat] = jsonFormat2(GoogleApiResult.apply[T]) 
} 
import AddressProtocol._ 

Есть ли способ получить только Location от json в ответе и избежать всего этого gumph?

код спрей-клиент:

implicit val system = ActorSystem("test-system") 
import system.dispatcher 

private val pipeline = sendReceive ~> unmarshal[GoogleApiResult[EachResult]] 

def getPostcode(postcode: String): Point = { 
    val url = s"http://maps.googleapis.com/maps/api/geocode/json?address=$postcode,+UK&sensor=true" 
    val future = pipeline(Get(url)) 
    val result = Await.result(future, 10 seconds) 
    result.results.size match { 
     case 0 => throw new PostcodeNotFoundException(postcode) 
     case x if x > 1 => throw new MultipleResultsException(postcode) 
     case _ => { 
      val location = result.results(0).geometry.location 
      new Point(location.lng, location.lat) 
     } 
    } 
} 

Или же, как я могу использовать джексон с распылением клиента?

+4

Вы можете попробовать https: // github.com/jrudolph/json-lenses/, который позволяет вам легко извлекать данные из JSON ast. – jrudolph

+1

Awesome, немного поиграл, но теперь он отлично выглядит. Разве это будет слито с брызгами? Должен быть!!! – shmish111

+0

Слияние с распылителем - это план, но мы в настоящее время не в состоянии сделать ход. – jrudolph

ответ

2

Следуя советам jrudolph для json-линз, я тоже немного поработал, но, наконец, получил работу. Мне было очень сложно (как новичок), и я уверен, что это решение далека от самого элегантного - тем не менее, я думаю, что это может помочь людям или вдохновить других на улучшения.

Учитывая JSON:

{ 
    "status": 200, 
    "code": 0, 
    "message": "", 
    "payload": { 
     "statuses": { 
      "emailConfirmation": "PENDING", 
      "phoneConfirmation": "DONE", 
     } 
    } 
} 

И дело класс для демаршаллизации statuses только:

case class UserStatus(emailConfirmation: String, phoneConfirmation: String) 

Можно сделать это, чтобы распаковать ответ:

import scala.concurrent.Future 
import spray.http.HttpResponse 
import spray.httpx.unmarshalling.{FromResponseUnmarshaller, MalformedContent} 
import spray.json.DefaultJsonProtocol 
import spray.json.lenses.JsonLenses._ 
import spray.client.pipelining._ 

object UserStatusJsonProtocol extends DefaultJsonProtocol { 
    implicit val userStatusUnmarshaller = new FromResponseUnmarshaller[UserStatus] { 
    implicit val userStatusJsonFormat = jsonFormat2(UserStatus) 
    def apply(response: HttpResponse) = try { 
     Right(response.entity.asString.extract[UserStatus]('payload/'statuses)) 
    } catch { case x: Throwable => 
     Left(MalformedContent("Could not unmarshal user status.", x)) 
    } 
    } 
} 
import UserStatusJsonProtocol._ 

def userStatus(userId: String): Future[UserStatus] = { 
    val pipeline = sendReceive ~> unmarshal[UserStatus] 
    pipeline(Get(s"/api/user/${userId}/status")) 
} 

 Смежные вопросы

  • Нет связанных вопросов^_^