5

由于文档还没有准备好,我会在这里询问 akka 维护人员。

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

Unmarshal(HttpResponse.entity).to[Person]

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

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

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

它不会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)

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

4

1 回答 1

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 的转换器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) }
  }
于 2015-07-05T13:56:38.303 回答