为什么 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) }
}
由于 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) }
}