原文地址:Marshalling and Unmarshalling
概览
序列化和反序列化同时在客户端和服务端使用。在服务端,它用于映射进来的请求至Scala或Java对象来输出相应。相似的,在客户端,它将用于序列化对象来传出HTTP请求和从进来的相应中反序列化它。这里有多种内容格式来序列化和反序列化,常见的有JSON和XML。
Akka HTTP 提供序列化/反序列化功能在 Scala marshalling/unmarshalling 和 Java marshalling/unmarshalling中阐述。同样的,有为Akka HTTP提供其他开源的序列化和反序列化,可用于不同格式和使用不同对象的序列化反序列实现。
squbs为手动序列化/反序列化提供JAVA API,以及添加在 Scala/Java 跨语言环境中工作工具。手动访问解析器和反解析器对于基于流的应用是有用的,在某些工作需要在流阶段完成。他同时对测试解析器配置式有用的,来保证实现正确的格式。
这篇文章讨论squbs提供的解析器和反解析器,你可以使用工具来手动调用这些解析器和反解析器。这个文档不再 作为 Akka HTTP路由DSL的一部分来阐述解析器和反解析器的作用。请查看Akka HTTP 路由 DSL Scala 和 Java 中的解析指令(包括在这篇文章中提供的)来使用解析器。
依赖
在你的 build.sbt
或scala构建文件中加入以下依赖:
"org.squbs" %% "squbs-ext" % squbsVersion
用法
JacksonMapperSupport
JacksonMapperSupport
提供基于当前流行的Jackson类库的JSON解析器和泛解析器。它允许全局的和单独的Jackson ObjectMapper
配置。
更多关于ObjectMapper
的配置细节请参见Jackson Data Binding documentation
Scala
import org.squbs.marshallers.json.JacksonMapperSupport._
自动和手动解析器都将在这个包中隐式的使用这个解释器。下面这个代码的例子展示了通过ObjectMapper
配置DefaultScalaModule
的不同方式。
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import org.squbs.marshallers.json.JacksonMapperSupport
/* To use DefaultScalaModule for all classes.
*/
JacksonMapperSupport.setDefaultMapper(
new ObjectMapper().registerModule(DefaultScalaModule))
/* To register a 'DefaultScalaModule' for marshalling a
* specific class, overrides global configuration for
* this class.
*/
JacksonMapperSupport.register[MyScalaClass](
new ObjectMapper().registerModule(DefaultScalaModule))
Java
解析器和反解析器可以从JacksonMapperSupport
的 marshaller
和 unmarshaller
方法中获取,将类的实例类型传递来序列化/反序列化如下:
import akka.http.javadsl.marshalling.Marshaller;
import akka.http.javadsl.model.HttpEntity;
import akka.http.javadsl.model.RequestEntity;
import akka.http.javadsl.unmarshalling.Unmarshaller;
import static org.squbs.marshallers.json.JacksonMapperSupport.*;
Marshaller<MyClass, RequestEntity> myMarshaller =
marshaller(MyClass.class);
Unmarshaller<HttpEntity, MyClass> myUnmarshaller =
unmarshaller(MyClass.class);
在本文中的讨论中,这些解析器可以作为Akka HTTP Routing DSL 的一部分或 invoking marshalling/unmarshalling的一部分使用。
下面的例子通过 ObjectMapper
配置 DefaultScalaModule
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.scala.DefaultScalaModule;
import org.squbs.marshallers.json.JacksonMapperSupport;
/* Globally registers the 'DefaultScalaModule'.
*/
JacksonMapperSupport.setDefaultMapper(
new ObjectMapper().registerModule(new DefaultScalaModule()));
/* This example below registers the 'DefaultScalaModule'
* just for 'MyClass'
*/
JacksonMapperSupport.register(MyClass.class
new ObjectMapper().registerModule(new DefaultScalaModule()));
XLangJsonSupport
XLangJsonSupport通过委托序列化和反序列化加入跨语言支持:
- Json4s for Scala classes
- Jackson for Java classes
这些通常是每个语言首选的解析器,无需更多的配置,他们即支持特定语言约定。他们同样对不同的约定通常有更好的优化。
然而,这个使用Json4s或Jackson的决定取决于用户序列化/反序列化传入的对象的类型。如果你有一个混合对象层次结构,你可能需要配置序列化/反序列化工具来支持不同的约定,如下所示:
Scala case class 引用Java Beans. 如果顶级对象是一个 Scala case class。 Json4s将被选择。然而它不知道如何序列化/反序列化 Java Beans。一个自定义的序列化需要加入到Json4来处理Java Bean。
Java Beans引用 Scala case class。如果顶级对象是Java Bean,Jackson将被选择。Jackson默认不支持如何序列化/反序列化这些 case class。你需要注册
DefaultScalaModule
至JacksonObjectMapper
来处理这些情况。
一个通用的序列化/反序列化混合语言对象层次结构的准则:除非Json4s优化是首选的,配置Jackson处理Scala更简单,只需要向ObjectMapper
注册DefaultScalaModule
。
像 JacksonMapperSupport
,它支持每种类型的解析器和反解析器配置。它允许配置Json4s 和 Jackson。
Scala
你只需要导入 XLangJsonSupport._
来暴露它在解析器和反解析器使用Scala代码范围内的隐藏成员。
自动和手动解析器将隐式使用这个包提供的解析器。下面提供配置XLangJsonSupport
的例子:
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule
import org.json4s.{DefaultFormats, jackson, native}
import org.squbs.marshallers.json.XLangJsonSupport
/* The following configures the default settings
* for 'XLangJsonSupport'
*/
// Adds ParameterNamesModule to Jackson
XLangJsonSupport.setDefaultMapper(
new ObjectMapper().registerModule(new ParameterNamesModule())
// Tells Json4s to use native serialization
XLangJsonSupport.setDefaultSerialization(native.Serialization)
// Adds MySerializer to the serializers used by Json4s
XLangJsonSupport.setDefaultFormats(DefaultFormats + MySerializer)
/* The following configures XLangJsonSupport for specific class.
* Namely, it configures for 'MyClass' and 'MyOtherClass'.
*/
// Use ParameterNamesModule for mashal/unmarshal MyClass
XLangJsonSupport.register[MyClass](new ParameterNamesModule()))
// Use Json4s Jackson serialization for MyOtherClass
XLangJsonSupport.register[MyOtherClass](jackson.Serialization)
// Use MySerializer Json4s serializer for MyOtherClass
XLangJsonSupport.register[MyOtherClass](DefaultFormats + MySerializer)
Java
解析器和反解析器可以从XLangJsonSupport
中的 marshaller
和unmarshaller
方法中获取,传递类实例的类型来序列化/反序列化,如下:
import akka.http.javadsl.marshalling.Marshaller;
import akka.http.javadsl.model.HttpEntity;
import akka.http.javadsl.model.RequestEntity;
import akka.http.javadsl.unmarshalling.Unmarshaller;
import static org.squbs.marshallers.json.XLangJsonSupport.*;
Marshaller<MyClass, RequestEntity> myMarshaller =
marshaller(MyClass.class);
Unmarshaller<HttpEntity, MyClass> myUnmarshaller =
unmarshaller(MyClass.class);
在本文讨论中,这些解析器和反解析器可以作为 Akka HTTP Routing DSL 的一部分或invoking marshalling/unmarshalling的一部分使用,如下:
下面提供配置XLangJsonSupport的例子:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.squbs.marshallers.json.XLangJsonSupport;
/* Global XLangJsonSupport Configuration.
*/
// Adds ParameterNamesModule to Jackson
XLangJsonSupport.setDefaultMapper(
new ObjectMapper().registerModule(new ParameterNamesModule());
// Tells Json4s to use native serialization
XLangJsonSupport.setDefaultSerialization(XLangJsonSupport.nativeSerialization());
// Adds MySerializer and MyOtherSerializer (varargs) to the serializers used by Json4s
XLangJsonSupport.addDefaultSerializers(new MySerializer(), new MyOtherSerializer());
/* Per-class configuration of 'XLangJsonSupport'.
* In this case we show configuring 'MyClass' and 'MyOtherClass'
*/
// Use ParameterNamesModule for mashal/unmarshal MyClass
XLangJsonSupport.register(MyClass.class, new ParameterNamesModule()));
// Use Json4s Jackson serialization for MyOtherClass
XLangJsonSupport.register(MyOtherClass.class, XLangJsonSupport.jacksonSerialization());
// Adds MySerializer and MyOtherSerializer (varargs) to the serializers used by Json4s for MyOtherClass
XLangJsonSupport.addSerializers(MyOtherClass.class, new MySerializer(), new MyOtherSerializer());
调用序列化/反序列化
除了使用解析器和反解析器作为Akka HTTP Routing DSL的一部分,手动调用序列化/反序列化常常用在服务端和客户端的流和测试中。
Scala
Akka提供 Scala DSL 来实现序列化和反序列化。它的使用例子可以如下所示:
import akka.actor.ActorSystem
import akka.http.scaladsl.marshalling.Marshal
import akka.http.scaladsl.model.MessageEntity
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.stream.ActorMaterializer
// We need the ActorSystem and Materializer to marshal/unmarshal
implicit val system = ActorSystem()
implicit val mat = ActorMaterializer()
// Also need the implicit marshallers provided by this import
import org.squbs.marshallers.json.XLangJsonSupport._
// Just call Marshal or Unmarshal as follows:
Marshal(myObject).to[MessageEntity]
Unmarshal(entity).to[MyType]
Java
用Akka HTTP's JavaDSL中定义的Marshaller
和 Unmarshaller
,MarshalUnmarshal
工具类来手动序列化和反序列化对象。例子如下:
import akka.actor.ActorSystem;
import akka.http.javadsl.model.RequestEntity;
import akka.stream.ActorMaterializer;
import akka.stream.Materializer;
import org.squbs.marshallers.MarshalUnmarshal;
// We're using JacksonMapperSupport here.
// But XLangJsonSupport works the same.
import static org.squbs.marshallers.json.JacksonMapperSupport.*;
// Base infrastructure, and the 'mu' MarshalUnmarshal.
private final ActorSystem system = ActorSystem.create();
private final Materializer mat = ActorMaterializer.create(system);
private final MarshalUnmarshal mu = new MarshalUnmarshal(system.dispatcher(), mat);
// Call 'apply' passing marshaller or unmarshaller as follows, using marshaller
// and unmarshaller methods from 'import static JacksonMapperSupport.*;':
CompletionStage<RequestEntity> mf = mu.apply(marshaller(MyClass.class), myObject);
CompletionStage<MyClass> uf = mu.apply(unmarshaller(MyClass.class), entity);