本文节选自《Scala Web开发》一书,完整内容见:https://www.yangbajing.me/scala-web-development/data/data.1.html
Jackson
Jackson是Java生态圈里最流行的JSON序列化库,它的官方网站是:https://github.com/FasterXML/jackson。
为什么选择 Jackson
为什么选择 Jackson 而不是更Scala范的play-json、circe、json4s等JSON序列化库呢?这里主要考虑是 Jackson 在Java生态圈里更流行,相对熟悉的人更多,可以一定程度上减轻Javaer们使用Scala时上手的难度。 同时,Jackson支持对大部分Java和Scala下的集合库、数据类型的JSON序列化,而大部分Scala范的JSON库只支持Scala的集合库、case class和数据类型。当你的应用里同时使用Java和Scala两种不同的集合类型和Java style class与Scala case class时,Jackson都可以对齐完美支持。
JacksonSupport
基于 Akka HTTP 的 marshal/unmarshal 机制,可以很容易的集成各种序列化/反序列化工具。akka-http-json 这套库就提供了9种不同的JSON序列化/反序列化方安供用户选择。
我们需要在 sbt 里添加依赖:
使用默认的 akka-http-jackson
可以看到,默认的 akka-http-jackson 不支持 Java 8 新提供的时间/日期类型序列化,这是因为它默认使用的 Jackson ObjectMapper 没有加载JavaTimeModule这个模块在 https://github.com/FasterXML/jackson-modules-java8/tree/master/datetime 可以找到JavaTimeModule这个模块的更多详细说明。
通过隐式值使用自定义的 ObjectMapper
首先来看看 akka-http-jackson 定义的 JacksonSupport.scala,它通过两个隐式函数实现了 Akka HTTP 的 Marshal/Unmarshal 功能。
可以看到隐式函数又分别定义了两个和一个隐式参数,而 这个隐式参数定义了默认值,这样在使用时我们就可以提供自定义的 ObjectMapper 来替代默认的 。先来看看怎样使用自定义的 ObjectMapper:
通过在代码上下文中定义一个隐式值:(变量名可以取任何名字,不需要是。但是需要保证在代码上下文中只有一个ObjectMapper隐式类型。),Scala 编译器在编译代码时将使用定义的隐式值传入函数或中以替代函数定义时设置的默认值。
自定义 ObjectMapper 定义在object Jackson.scala:
自定义反序列化时允许的MediaType类型
默认情况下,JacksonSupport要求客户端提交的HTTP请求必需设置Content-Type的mime-type类型为:,但很多时候会遇到不那么规范的客户端,它们并未正确的设置HTTP请求头。这时我们可以自定义JacksonSupport让它在反序列化时支持其它Content-Type:这里定义除了外还支持类型的请求。
在 routing DSL 里使用
在 Akka HTTP Routing DSL 里使用Jackson来反序列化/序列化JSON就非常简单了。通过指令来将提交的JSON数据解析成 样本类(将调用 隐式函数),在函数响应结果时将 对象序列化成JSON字符串并设置对应的Content-Type(调用 隐式函数)。
总结
Akka HTTP通过强大的 Marshal/Unmarshal 机制来实现数据的序列/反序列化,作为一款工具库 Akka HTTP 提供了足够的灵活性,用户可以选择自己喜欢的序列/反序列化工具和使用方式。对于JSON,推荐从https://github.com/hseeberger/akka-http-json开始,上面很有可能找到你想要的。同时,akka-http-json也是一个不错的学习 Akka HTTP Marshal/Unmarshal 机制的样例。
完整的测试代码在:data/src/test/scala/scalaweb/data/json/jackson/JacksonSupportTest.scala,可以通过以下命令来运行它:
测试结果示例:
领取专属 10元无门槛券
私享最新 技术干货