为什么akka-http Unmarshaler返回Future [T]而不是T?

时间:2015-07-04 16:49:12

标签: scala akka spray spray-client akka-http

由于here还没有准备好,我会在这里问akka维护者。

为什么akka-http A会返回Unmarshaler而不是Future[T]?这是我的目标。我想从XML http响应中解组类,就像它为json所做的一样。例如,我想写

T

case case及其unmarshaller看起来像这样

Unmarshal(HttpResponse.entity).to[Person]

它不会使用1.0-RC4提供的case class Person(name: String, age: Int) implicit val personUnmarshaller = Unmarshaller[NodeSeq, Person] { _ => xml => Future(Person((xml \\ "name").text, (xml \\ "age").text.toInt)) } 进行编译,因为范围内没有ScalaXmlSupport。因此,为了欺骗它,我写了两个隐式转换

Unmarshaller[ResponseEntity,Person]

它有效,但我不喜欢丑陋的implicit def xmlUnmarshallerConverter[T](marsh: Unmarshaller[NodeSeq, T])(implicit mat: Materializer): FromEntityUnmarshaller[T] = xmlUnmarshaller(marsh, mat) implicit def xmlUnmarshaller[T](implicit marsh: Unmarshaller[NodeSeq, T], mat: Materializer): FromEntityUnmarshaller[T] = defaultNodeSeqUnmarshaller.map(Unmarshal(_).to[T].value.get.get) 。是否有更优雅的方式来实现这个?

1 个答案:

答案 0 :(得分:4)

好吧,我现在已经实现了自己的解决方案,但我希望Akka团队能够使同步/异步内容在库中保持一致。

所以我创建了Unmarshaller的简单克隆,其定义如下

trait SyncUnmarshaller[-A, B] {
  def apply(value: A): B
}

object SyncUnmarshaller {
  def apply[A, B](f: A => B): SyncUnmarshaller[A, B] =
    new SyncUnmarshaller[A, B] {
      def apply(a: A) = f(a)
    }
}

object SyncUnmarshal {
  def apply[T](value: T): SyncUnmarshal[T] = new SyncUnmarshal(value)
}

class SyncUnmarshal[A](val value: A) {
  def to[B](implicit um: SyncUnmarshaller[A, B]): B = um(value)
}

因此,域类的解组者将被定义为

implicit val articleBodyUnmarshaller = SyncUnmarshaller[NodeSeq, ArticleBody] { xml =>
  ArticleBody(xml.toString())
}

然后我已经提到ScalaXmlSupport有两个含义

implicit def xmlUnmarshallerConverter[T](marshaller: SyncUnmarshaller[NodeSeq, T])(implicit mat: Materializer): FromEntityUnmarshaller[T] =
  xmlUnmarshaller(marshaller, mat)

implicit def xmlUnmarshaller[T](implicit marshaller: SyncUnmarshaller[NodeSeq, T], mat: Materializer): FromEntityUnmarshaller[T] = {
  defaultNodeSeqUnmarshaller.map(marshaller(_))

那就是它。最后,如果您想使用Akka的调用,如

Unmarshal(response.entity).to[Article].map(Right(_))

您需要从我的SyncUnmarshaller转换为akka' s Unmarshaller

implicit def syncToAsyncConverter[A, B](marshaller: SyncUnmarshaller[A, B]): Unmarshaller[A, B] =
  new Unmarshaller[A, B] {
    def apply(a: A)(implicit ec: ExecutionContext) =
      try FastFuture.successful(marshaller(a))
      catch { case NonFatal(e) ⇒ FastFuture.failed(e) }
  }