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转换:
PredefinedFromStringUnmarshallersByteShortIntLongFloatDoubleBooleanPredefinedFromEntityUnmarshallersArray[Byte]ByteStringArray[Char]Stringakka.http.scaladsl.model.FormDataGenericUnmarshallersUnmarshaller[T, T] (identity unmarshaller)Unmarshaller[Option[A], B], if an Unmarshaller[A, B] is availableUnmarshaller[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.Unmarshalimport 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 DefaultJsonProtocolobject 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.Unmarshalimport 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 DefaultJsonProtocolobject 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.Json4sSupportimport org.json4s.jacksonimport 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 JsonCodecobject 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")) ???}}}
Akka(34): Http:Unmarshalling,from Json
原文地址:http://www.cnblogs.com/tiger-xc/p/7763466.html