zoukankan      html  css  js  c++  java
  • Akka(34): Http:Unmarshalling,from Json

      Unmarshalling是Akka-http内把网上可传输格式的数据转变成程序高级结构话数据的过程,比如把Json数据转换成某个自定义类型的实例。按具体流程来说就是先把Json转换成可传输格式数据如:MessageEntity,HttpRequest,HttpReponse等,然后再转换成程序高级结构数据如classXX实例。Unmarshalling对一个A类实例到B类实例的转换是通过Unmarshaller[A,B]来实现的:

    trait Unmarshaller[-A, B] extends akka.http.javadsl.unmarshalling.Unmarshaller[A, B] {...}
    object Unmarshaller
      extends GenericUnmarshallers
      with PredefinedFromEntityUnmarshallers
      with PredefinedFromStringUnmarshallers {
    
      // format: OFF
    
      //#unmarshaller-creation
      /**
       * Creates an `Unmarshaller` from the given function.
       */
      def apply[A, B](f: ExecutionContext ⇒ A ⇒ Future[B]): Unmarshaller[A, B] =
        withMaterializer(ec => _ => f(ec))
    ...}

    从Unmarshaller的构建函数apply可以估计它的作用应该与函数A=>Future[B]很相似。A代表网上可传输类型如MessageEntity、HttpRequest,B代表某种程序高级数据类型。因为A到B的转换是non-blocking的,所以可以立即返回Future类型结果。Akka-http按被转换对象类型分类命名了下面这些类型别名:

    type FromEntityUnmarshaller[T] = Unmarshaller[HttpEntity, T]
    type FromMessageUnmarshaller[T] = Unmarshaller[HttpMessage, T]
    type FromResponseUnmarshaller[T] = Unmarshaller[HttpResponse, T]
    type FromRequestUnmarshaller[T] = Unmarshaller[HttpRequest, T]
    type FromByteStringUnmarshaller[T] = Unmarshaller[ByteString, T]
    type FromStringUnmarshaller[T] = Unmarshaller[String, T]
    type FromStrictFormFieldUnmarshaller[T] = Unmarshaller[StrictForm.Field, T]

    Akka-http对以下类型提供了自动的Unmarshalling转换: 

    PredefinedFromStringUnmarshallers
    Byte
    Short
    Int
    Long
    Float
    Double
    Boolean
    PredefinedFromEntityUnmarshallers
    Array[Byte]
    ByteString
    Array[Char]
    String
    akka.http.scaladsl.model.FormData
    GenericUnmarshallers
    Unmarshaller[T, T] (identity unmarshaller)
    Unmarshaller[Option[A], B], if an Unmarshaller[A, B] is available
    Unmarshaller[A, Option[B]], if an Unmarshaller[A, B] is available

    也就是说Akka-http提供了这些U类型的Unmarshaller[U,B]隐式实例。Akka-http也提供了工具类型Unmarshal:

    object Unmarshal {
      def apply[T](value: T): Unmarshal[T] = new Unmarshal(value)
    }
    
    class Unmarshal[A](val value: A) {
      /**
       * Unmarshals the value to the given Type using the in-scope Unmarshaller.
       *
       * Uses the default materializer [[ExecutionContext]] if no implicit execution context is provided.
       * If you expect the marshalling to be heavy, it is suggested to provide a specialized context for those operations.
       */
      def to[B](implicit um: Unmarshaller[A, B], ec: ExecutionContext = null, mat: Materializer): Future[B] = {
        val context: ExecutionContext = if (ec == null) mat.executionContext else ec
    
        um(value)(context, mat)
      }
    }

    我们可以通过Unmarshal.to[B]把Unmarshal[A]转换成Future[B]。注意:这一步只包括了从网上可传输类型到程序类型转换这一过程,不包括具体实现时的Json转换。下面是一些Unmarshal的用例:

    import akka.actor._
    import akka.stream._
    import akka.http.scaladsl.unmarshalling.Unmarshal
    import akka.http.scaladsl.model._
    import akka.http.scaladsl.server.Directives._
    
    object Unmarshalling {
      implicit val httpSys = ActorSystem("httpSystem")
      implicit val httpMat = ActorMaterializer()
      implicit val httpEC = httpSys.dispatcher
    
      val futInt = Unmarshal(43).to[Int]
      val futBoolean = Unmarshal("0").to[Boolean]
      val futString = Unmarshal(HttpEntity("Hello")).to[String]
      val futHello = Unmarshal(HttpRequest(method = HttpMethods.GET, entity = HttpEntity("hello")))
    
    }

    以上都是已知类型之间转换,可能没什么实际用途,不像marshalling:中间层Marshalling有实际转换的需要。Unmarshalling可以直接进行Json到自定义类型之间的转换,如:

     val route = (path("User") & post) { entity(as[User]){ user =>
        complete(Future(s"inserting user: $user"))
      }} ~
        (path("Item"/IntNumber) & put) { id => entity(as[Item]){ item =>
          complete(Future(s"update item $id: $item"))
        }}

    以上是通过Directive as[???]实现的:

     /**
       * Returns the in-scope [[FromRequestUnmarshaller]] for the given type.
       *
       * @group marshalling
       */
      def as[T](implicit um: FromRequestUnmarshaller[T]) = um

    这需要把FromRequestUmarshaller[T]放在可视域内,FromRequestUmarshaller[T]实际是Unmarshaller[T,B]的别名: 

    type FromRequestUnmarshaller[T] = Unmarshaller[HttpRequest, T]

    在上篇讨论我们介绍了Akka-http的Marshalling是type-class模式的。其中关键可以参考上篇讨论。现在我们需要这些Unmarshaller的隐式实例:

    trait Formats extends SprayJsonSupport with DefaultJsonProtocol
    object Converters extends Formats {
      case class User(id: Int, name: String)
      case class Item(id: Int, name: String, price: Double)
      implicit val itemFormat = jsonFormat3(Item.apply)
      implicit val userFormat = jsonFormat2(User.apply)
    }
    
    object Unmarshalling {
      import Converters._
    ...

    如果使用Json4s的实现方式,我们需要如下提供这些隐式实例:

    trait JsonCodec extends Json4sSupport {
      import org.json4s.DefaultFormats
      import org.json4s.ext.JodaTimeSerializers
      implicit val serilizer = jackson.Serialization
      implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
    }
    object JsConverters extends JsonCodec

    Json4s的具体用例如下:

      import scala.collection.mutable._
      case class User(id: Int, name: String)
      class Item(id: Int, name: String, price: Double)
      object AnyPic {
        val area = 10
        val title = "a picture"
        val data = ArrayBuffer[Byte](1,2,3)
      }
    
      val route = (path("User") & post) { entity(as[User]){ user =>
        complete(Future(s"inserting user: $user"))
      }} ~
        (path("Item"/IntNumber) & put) { id => entity(as[Item]){ item =>
          complete(Future(s"update item $id: $item"))
        }} ~
        (path("Picture") & put) { entity(as[AnyPic.type]){ pic =>
          complete(Future(s"insert picture: $pic"))
        }}

    从功能上和表达灵活性来讲,Json4s的实现方式要占优。

    下面就是本次讨论的示范源代码:

    Unmarshalling

    import akka.actor._
    import akka.stream._
    import akka.http.scaladsl.unmarshalling.Unmarshal
    import akka.http.scaladsl.model._
    import akka.http.scaladsl.server.Directives._
    import scala.concurrent._
    import akka.http.scaladsl.marshallers.sprayjson._
    import spray.json._
    
    trait Formats extends SprayJsonSupport with DefaultJsonProtocol
    object Converters extends Formats {
      case class User(id: Int, name: String)
      case class Item(id: Int, name: String, price: Double)
      implicit val itemFormat = jsonFormat3(Item.apply)
      implicit val userFormat = jsonFormat2(User.apply)
    }
    
    object Unmarshalling {
      import Converters._
      implicit val httpSys = ActorSystem("httpSystem")
      implicit val httpMat = ActorMaterializer()
      implicit val httpEC = httpSys.dispatcher
    
      val futInt = Unmarshal(43).to[Int]
      val futBoolean = Unmarshal("0").to[Boolean]
      val futString = Unmarshal(HttpEntity("Hello")).to[String]
      val futHello = Unmarshal(HttpRequest(method = HttpMethods.GET, entity = HttpEntity("hello")))
    
      val route = (path("User") & post) { entity(as[User]){ user =>
        complete(Future(s"inserting user: $user"))
      }} ~
        (path("Item"/IntNumber) & put) { id => entity(as[Item]){ item =>
          complete(Future(s"update item $id: $item"))
        }}
    
    }

    Json4sUnmarshalling

    import akka.actor._
    import akka.stream._
    import akka.http.scaladsl.server.Directives._
    import de.heikoseeberger.akkahttpjson4s.Json4sSupport
    import org.json4s.jackson
    import scala.concurrent._
    trait JsonCodec extends Json4sSupport {
      import org.json4s.DefaultFormats
      import org.json4s.ext.JodaTimeSerializers
      implicit val serilizer = jackson.Serialization
      implicit val formats = DefaultFormats ++ JodaTimeSerializers.all
    }
    object JsConverters extends JsonCodec
    
    
    object Json4sUnmarshalling {
      import JsConverters._
      implicit val httpSys = ActorSystem("httpSystem")
      implicit val httpMat = ActorMaterializer()
      implicit val httpEC = httpSys.dispatcher
    
      import scala.collection.mutable._
      case class User(id: Int, name: String)
      class Item(id: Int, name: String, price: Double)
      object AnyPic {
        val area = 10
        val title = "a picture"
        val data = ArrayBuffer[Byte](1,2,3)
      }
    
      val route = (path("User") & post) { entity(as[User]){ user =>
        complete(Future(s"inserting user: $user"))
      }} ~
        (path("Item"/IntNumber) & put) { id => entity(as[Item]){ item =>
          complete(Future(s"update item $id: $item"))
        }} ~
        (path("Picture") & put) { entity(as[AnyPic.type]){ pic =>
          complete(Future(s"insert picture: $pic"))
        }}
    }

     

    
    

     

     

     

     

     

  • 相关阅读:
    HDU1005 Number Sequence 题解 矩阵快速幂
    HDU1003 Max Sum 题解 动态规划 最大字段和扩展
    HDU1002 A + B Problem II 题解 高精度加法
    python练习题之访问限制
    python练习之析构函数
    python练习题之 猫2
    python 练习题之 猫
    练习题之交换牌
    mongodb 安装教程
    pymongo.errors.ServerSelectionTimeoutError: localhost:27017: [Errno 111] Connection refused
  • 原文地址:https://www.cnblogs.com/tiger-xc/p/7763466.html
Copyright © 2011-2022 走看看