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

标签 scala akka spray spray-client akka-http

documentation还没准备好我会在这里问 akka 维护者。

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

Unmarshal(HttpResponse.entity).to[Person]

case 类及其解码器如下所示
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 .有没有更优雅的方法来实现这个?

最佳答案

好吧,我现在已经实现了我自己的解决方案,但我希望 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) }
  }

关于scala - 为什么 akka-http Unmarshaler 返回 Future[T] 而不是 T?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31223016/

相关文章:

java - playframework模板报价/报价规则

scala - 如何在 Scala 中编写高效的 groupBy-size 过滤器,可以近似

scala - 如何对整数列表求和并将每一步保存到新列表?

java - Akka Actor 和消息限制

scala - 如何从spark将文件写入cassandra

scala - Actors 中 future 的执行上下文

authentication - Akka 验证OAuth2Async : credentials missing

scala - 喷雾路线得到童星回应

json - 将Scala案例类转换为json

scala - 部署静态文件的方法是什么,以便 Spray 可以为它们提供服务?