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

exp*_*ert 5 scala akka spray spray-client akka-http

由于文档尚未准备好,我将在这里询问 akka 维护人员。

为什么 akka-httpUnmarshaler返回Future[T]而不是T?这是我的目标。我想从 XML http 响应中解组类,类似于对 json 的处理方式。例如我想写

Unmarshal(HttpResponse.entity).to[Person]
Run Code Online (Sandbox Code Playgroud)

其中案例类及其解组器看起来像这样

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

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

它不会ScalaXmlSupport使用 1.0-RC4 提供的版本进行编译,因为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)
Run Code Online (Sandbox Code Playgroud)

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

exp*_*ert 4

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

\n\n

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

\n\n
trait SyncUnmarshaller[-A, B] {\n  def apply(value: A): B\n}\n\nobject SyncUnmarshaller {\n  def apply[A, B](f: A => B): SyncUnmarshaller[A, B] =\n    new SyncUnmarshaller[A, B] {\n      def apply(a: A) = f(a)\n    }\n}\n\nobject SyncUnmarshal {\n  def apply[T](value: T): SyncUnmarshal[T] = new SyncUnmarshal(value)\n}\n\nclass SyncUnmarshal[A](val value: A) {\n  def to[B](implicit um: SyncUnmarshaller[A, B]): B = um(value)\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

因此域类的解组器将像这样定义

\n\n
implicit val articleBodyUnmarshaller = SyncUnmarshaller[NodeSeq, ArticleBody] { xml =>\n  ArticleBody(xml.toString())\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

ScalaXmlSupport那么我已经提到了两个隐含的内容

\n\n
implicit def xmlUnmarshallerConverter[T](marshaller: SyncUnmarshaller[NodeSeq, T])(implicit mat: Materializer): FromEntityUnmarshaller[T] =\n  xmlUnmarshaller(marshaller, mat)\n\nimplicit def xmlUnmarshaller[T](implicit marshaller: SyncUnmarshaller[NodeSeq, T], mat: Materializer): FromEntityUnmarshaller[T] = {\n  defaultNodeSeqUnmarshaller.map(marshaller(_))\n
Run Code Online (Sandbox Code Playgroud)\n\n

就是这样。最后,如果你想使用 Akka 的调用,例如

\n\n

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

\n\n

你需要我的转换器SyncUnmarshaller到 akka's 的转换器Unmarshaller

\n\n
implicit def syncToAsyncConverter[A, B](marshaller: SyncUnmarshaller[A, B]): Unmarshaller[A, B] =\n  new Unmarshaller[A, B] {\n    def apply(a: A)(implicit ec: ExecutionContext) =\n      try FastFuture.successful(marshaller(a))\n      catch { case NonFatal(e) \xe2\x87\x92 FastFuture.failed(e) }\n  }\n
Run Code Online (Sandbox Code Playgroud)\n