2015-11-22 6 views
4

У меня проблема с демонтажем объектов Json с помощью спрей - акка.Spray Akka Json Unmarshalling

Когда я хотел бы использовать актеров, которые возвращают Future [List [Person]], он не работает.

Если я непосредственно использую объект dao, он работает.

Вот мои коды:

PersonDao.scala

import scala.concurrent.ExecutionContext.Implicits.global 
import scala.concurrent.Future 

case class Person(id: Int, name: String, surname: String) 

object PersonDao { 

    def getAll: Future[List[Person]] = Future { 
    List[Person](Person(1, "Bilal", "Alp"), Person(2, "Ahmet", "Alp")) 
    } 
} 

EntityServiceActor.scala

import akka.actor.Actor 
import com.bilalalp.akkakafka.model.PersonDao 
import com.bilalalp.akkakafka.service.ServiceOperation.FIND_ALL 

object ServiceOperation { 

    case object FIND_ALL 

} 

class EntityServiceActor extends Actor { 

    override def receive: Receive = { 

    case FIND_ALL => PersonDao.getAll 
    } 
} 

ServerSupervisor.scala

import akka.actor.{Actor, ActorRefFactory} 
import com.bilalalp.akkakafka.webservice.TaskWebService 
import spray.routing.RejectionHandler.Default 


class ServerSupervisor extends Actor with PersonWebService { 

    implicit val system = context.system 

    override def receive: Receive = runRoute(entityServiceRoutes) 

    override implicit def actorRefFactory: ActorRefFactory = context 
} 

WebServiceTrait.scala

import akka.util.Timeout 

import spray.routing.HttpService 

import scala.concurrent.duration._ 
import scala.language.postfixOps 

import org.json4s.NoTypeHints 
import org.json4s.native.Serialization._ 

trait WebServiceTrait extends HttpService { 

    implicit def executionContext = actorRefFactory.dispatcher 

    implicit val json4sFormats = formats(NoTypeHints) 

    implicit val timeout = Timeout(120 seconds) 
} 

PersonWebService.scala

trait PersonWebService extends WebServiceTrait with Json4sSupport { 

    val json3sFormats = DefaultFormats 

    val entityServiceWorker = actorRefFactory.actorOf(Props[EntityServiceActor], "entityServiceActor") 

    val entityServiceRoutes = { 
    pathPrefix("person") { 
     pathEndOrSingleSlash { 
     get { 
      ctx => ctx.complete((entityServiceWorker ? FIND_ALL).mapTo[Person]) 
     } 
     } 
    } 
    } 
} 

Application.scala

import akka.actor.{ActorRef, ActorSystem, Props} 
import akka.io.IO 
import com.bilalalp.akkakafka.server.ServerSupervisor 
import spray.can.Http 


object Application extends App { 

    implicit val system = ActorSystem("actorSystem") 

    val mainHandler: ActorRef = system.actorOf(Props[ServerSupervisor]) 
    IO(Http)! Http.Bind(mainHandler, interface = Configuration.appInterface, port = Configuration.appPort) 

} 

Когда я запускаю этот код, он ничего не дает и ждет какое-то время.

После ожидания браузера дает это сообщение:

сервер был не в состоянии производить своевременный ответ на запрос.

и выход консоли

[ОШИБКА] [11/22/2015 21: 15: 24,109] [actorSystem-akka.actor.default-диспетчерская-7] [akka.actor .ActorSystemImpl (actorSystem)] Ошибка при обработке запроса HttpRequest (GET, http://localhost:3001/person/,List(Host: : localhost: 3001, Connection: keep-alive, Cache-C ontrol: no-cache, Pragma: no-cache, User-Agent: Mozilla /5.0 (Windows NT 6.3, WOW64) AppleWebKit/537.36 (KHTML, как и Gecko) Maxthon/4.4.6.1000 C hrome/30.0.1599.101 Safari/537.36, DNT: 1, Accept-Encoding: gzip, deflate, Accept-язык: tr-TR), Empty, HTTP/1.1) akka.pattern.AskTimeoutException: запросить тайм-аут на [ Актер [akka: // actorSystem/user/$ a/entityServiceActor # -1810673919]] после [120000 мс]. Отправитель [null] отправил сообщение типа "com.bilalalp.akkakafka.service.ServiceOperation $ FIND_ALL $". at akka.pattern.PromiseActorRef $$ anonfun $ 1.apply $ mcV $ sp (AskSupport.scala: 415) at akka.actor.Scheduler $$ anon $ 7.run (Scheduler.scala: 132) at scala.concurrent. Будущее $ InternalCallbackExecutor $ .unbatchedExecute (Future.scala: 599) at scala.concurrent.BatchingExecutor $ class.выполнить (BatchingExecutor.scala: 109) в scala.concurrent.Future $ InternalCallbackExecutor $ .Execute (Future.scala: 597)

Если я изменить PersonWebService.scala к этому:

trait PersonWebService extends WebServiceTrait with Json4sSupport { 

    val json3sFormats = DefaultFormats 

    val entityServiceWorker = actorRefFactory.actorOf(Props[EntityServiceActor], "entityServiceActor") 

    val entityServiceRoutes = { 
    pathPrefix("person") { 
     pathEndOrSingleSlash { 
     get (
//     ctx => ctx.complete((entityServiceWorker ? FIND_ALL).mapTo[Person]) 
      ctx => ctx.complete(PersonDao getAll) 
     ) 
     } 
    } 
    } 
} 

It работ и выход:

[{ "ID": 1, "имя": "Билал", "фамилия": "Alp"}, { "ID": 2, "имя": "Ахмет" , "фамилия": "Алп"}]

Я бы хотел использовать актеров в аэрозолях. Я не знаю, является ли это плохой практикой или нет, потому что я новичок в акке и спрей.

Как я могу это решить? Есть идеи?

спасибо.

ответ

3

Вам нужно отправить результат обратно отправителю:

case FIND_ALL => 
    PersonDao.getAll.pipeTo(sender()) 
+0

Хотя этот код может ответить на вопрос, обеспечивая дополнительный контекст относительно того, почему и/или, как этот код отвечает на вопрос улучшает его долгосрочную ценность. – dotctor

+0

@Timothy Kim Я добавил: case FIND_ALL => sender()! PersonDao.getAll, но он не дает никакой ошибки, но я не вижу результат json. Он возвращает этот ответ {}. Что мне делать? –

+0

'.mapTo [Person]' должен быть '.mapTo [List [Person]]', как уже было сказано выше. –

4

Прежде всего, Вы можете ввести (PersonWebService.scala):

pathEndOrSingleSlash { 
    get { 
     complete { 
     (entityServiceWorker ? FindAll).mapTo[List[Person]] 
    } 
    } 

И как @Timothy Ким сказал, что вы необходимо отправить результаты с помощью «sender! getAll.onComplete

Как я вижу getAll возвращает Будущее, поэтому, на мой взгляд, лучше всего разрешить его в EntityServiceActor.scala:

// import the pipe pattern (see pipeTo below): 
import akka.pattern.pipe 
import context.dispatcher 

override def receive: Receive = { 
    case FindAll => 
    PersonDao.getAll() 
     .recover({ case err => List() /* could log error here */ }) 
     .pipeTo(sender()) // do this instead of onComplete, it's safer 

в этом простом случае GETALL будущее будет решен, если все в порядке, услуга будет получить список лиц, в противном случае список будет пуст.

О, и еще одна вещь PersonWebService.scala должны .mapTo [Список [Person]]

+0

Я сделал все, что вы сказали. Он дает эту ошибку: java.lang.ClassCastException: не может наложить scala.runtime.BoxedUnit на scala.collection.immutable.List на java.lang.Class.cast (Class.java:3369) –

+0

Я немного улучшил фрагмент кода , чтобы использовать лучшие практики здесь - pipeTo, а также восстановление в случае сбоя фьючерсов –