编译以下 Scala 代码:
import spray.json.DefaultJsonProtocol._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.server.Directives.complete
case class Item(name: String, id: Long)
implicit val itemFormat = jsonFormat2(Item)
val item = Item("xbox", 123)
complete(item)
工作表中的输出如下:
import spray.json.DefaultJsonProtocol._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import akka.http.scaladsl.server.Directives.complete
defined class Item
itemFormat: spray.json.RootJsonFormat[Item] = spray.json.ProductFormatsInstances$$anon$2@4528e00
item: Item = Item(xbox,123)
res0: akka.http.scaladsl.server.StandardRoute = <function1>
但是当我注释掉 import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
时,出现以下编译错误:
Error:(11, 11) type mismatch;
found : A$A562.this.Item
required: akka.http.scaladsl.marshalling.ToResponseMarshallable
complete(item);}
^
该导入有何影响?
最佳答案
当您执行 RequestContext#complete(response)
时,它采用 ToResponseMarshallable
作为输入。
package akka.http.scaladsl.server
@InternalApi
private[http] class RequestContextImpl(
override def complete(trm: ToResponseMarshallable): Future[RouteResult] =
trm(request)(executionContext)
.fast.map(res ⇒ RouteResult.Complete(res))(executionContext)
.fast.recover {
case Marshal.UnacceptableResponseContentTypeException(supported) ⇒
RouteResult.Rejected(UnacceptedResponseContentTypeRejection(supported) :: Nil)
case RejectionError(rej) ⇒
RouteResult.Rejected(rej :: Nil)
}(executionContext)
}
SprayJsonSupport
是定义隐式 Marshallers
的对象,它们是提供 Marshallable
package akka.http.scaladsl.marshallers.sprayjson
trait SprayJsonSupport {
implicit def sprayJsonMarshallerConverter[T](writer: RootJsonWriter[T])(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
sprayJsonMarshaller[T](writer, printer)
implicit def sprayJsonMarshaller[T](implicit writer: RootJsonWriter[T], printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[T] =
sprayJsValueMarshaller compose writer.write
implicit def sprayJsValueMarshaller(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[JsValue] =
Marshaller.StringMarshaller.wrap(MediaTypes.`application/json`)(printer)
}
如果您不导入 SprayJsonSupport
,您将不会获得隐式 Marshallers
来将您的案例类编码到所需的输出,即 JSObject
.
如果您不想导入为 JsonMarshallers 提供默认值的 SprayJsonSupport
,请自行编写或从 JsonSpraySupport
复制粘贴编码器。
示例
object GetHttpRoutes {
case class Acknowledge(status: String)
implicit val itemFormat = jsonFormat1(Acknowledge)
implicit def toJsonMarshallerConverter[Entity](writer: RootJsonWriter[Entity])(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[Entity] =
toJsonMarshaller[Entity](writer, printer)
implicit def toJsonMarshaller[Entity](implicit writer: RootJsonWriter[Entity], printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[Entity] =
toJsValueMarshaller compose writer.write
implicit def toJsValueMarshaller(implicit printer: JsonPrinter = CompactPrinter): ToEntityMarshaller[JsValue] =
Marshaller.StringMarshaller.wrap(MediaTypes.`application/json`)(printer)
val get_api =
path("") {
get { context =>
context.complete {
Acknowledge(status = "xbox")
}
}
}
}
trait HTTPRoutes {
implicit val system: ActorSystem
implicit val materializer: ActorMaterializer
val route = GetHttpRoutes.get_api
}
测试
class GetHttpRoutesCompSpecs extends WordSpec with Matchers with ScalatestRouteTest with BeforeAndAfterAll {
"HTTP GET endpoints" should {
"returns xbox on /" in {
Get("/") ~> GetHttpRoutes.get_api ~> check {
responseAs[String] shouldEqual """{"status":"xbox"}"""
}
}
}
}
关于scala - Akka HTTP 编码(marshal)处理在幕后是如何实现的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45068547/