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

Why akka-http Unmarshaler returns Future[T] instead of T?

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

为什么 akka-http Unmarshaler returns Future[T] 而不是 T ?这是我的目标。我想从 XML HTTP 响应中解组 class,与 json 的处理方式类似。例如我想写

Unmarshal(HttpResponse.entity).to[Person]

其中 case class 及其解组器如下所示

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

implicit val personUnmarshaller = Unmarshaller[NodeSeq, Person] { _ => xml =>
      Future(Person((xml \ "name").text, (xml \ "age").text.toInt))
}

它不会用 1.0-RC4 提供的 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)

可以,但我不喜欢丑的.value.get.get。有没有更优雅的方法来实现这个?

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

所以我创建了 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 的 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) }
  }