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。有没有更优雅的方法来实现这个?
好吧,我现在已经实现了自己的解决方案,但我希望 Akka 团队能够使库中的同步/异步内容保持一致。
\n\n所以我创建了简单的克隆Unmarshaller定义如下
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}\nRun Code Online (Sandbox Code Playgroud)\n\n因此域类的解组器将像这样定义
\n\nimplicit val articleBodyUnmarshaller = SyncUnmarshaller[NodeSeq, ArticleBody] { xml =>\n ArticleBody(xml.toString())\n}\nRun Code Online (Sandbox Code Playgroud)\n\nScalaXmlSupport那么我已经提到了两个隐含的内容
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(_))\nRun Code Online (Sandbox Code Playgroud)\n\n就是这样。最后,如果你想使用 Akka 的调用,例如
\n\nUnmarshal(response.entity).to[Article].map(Right(_))
你需要我的转换器SyncUnmarshaller到 akka's 的转换器Unmarshaller
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 }\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
1517 次 |
| 最近记录: |