Jen*_*zlo 10 json scala marshalling unmarshalling akka-http
我的应用程序支持protobuf和JSON序列化.对于我使用的JSON序列化com.trueaccord.scalapb.json.JsonFormat,我的dtos是从proto定义生成的.
该com.trueaccord串行包装选项类型,这是造成某些客户端的问题,所以我希望能够支持JSON对象org.json4s没有制动现有的客户.
我希望能够根据名为JFORMAT的自定义http头选择一个序列化程序.我的想法是,如果发送此标头,我将使用json4s,否则我将使用trueaccord序列化器.
我设法创建一个Unmarshaller,它可以根据标头值选择一个请求序列化器:
Unmarshaller.withMaterializer[HttpRequest, T](_ => implicit mat => {
case request: HttpRequest =>
val entity = request.entity
entity.dataBytes.runFold(ByteString.empty)(_ ++ _).map(data => {
entity.contentType match {
case `applicationJsonContentType` =>
val jsFormat = {
val header = request.headers.find(h => h.name() == jsonFormatHeaderName)
if (header.isEmpty) "1.0" else header.get.value()
}
val charBuffer = Unmarshaller.bestUnmarshallingCharsetFor(entity)
val jsonText = data.decodeString(charBuffer.nioCharset().name())
val dto = if(jsFormat == "2.0") {
write[T](value)(formats) // New Formatter
} else {
JsonFormat.fromJsonString[T](jsonText) // Old Formatter
}
dto
case `protobufContentType` =>
companion.parseFrom(CodedInputStream.newInstance(data.asByteBuffer)) // Proto Formatter
case _ =>
throw UnsupportedContentTypeException(applicationJsonContentType, protobufContentType)
}
})
Run Code Online (Sandbox Code Playgroud)
我想要做同样与我的Marshaller我与Marshaller.oneOf和JSON处理一个看起来像使用:
Marshaller.withFixedContentType(contentType) { value =>
val jsonText = JsonSerializer.toJsonString[T](value)
HttpEntity(contentType, jsonText)
}
Run Code Online (Sandbox Code Playgroud)
有没有办法构建一个知道请求http标头的Mashaller?在阿卡HTTP文档没有任何例子,我不能让PredefinedToRequestMarshallers感.
我是否需要以某种方式组合多个marshallers,或者我可以在请求序列化期间将一些元数据附加到上下文中,我可以稍后在Marshaller中使用它?我希望尽可能避免将meta附加到我的dto或使用自定义内容类型application/vnd.api+json
当我将响应格式化为Accept-Encoding,自定义标头(如唯一请求ID)以创建相关ID时,我可以从请求中使用许多其他有用的信息,我可以通过读取callback查询参数来添加JSONP支持等.
澄清一下:我需要一个解决方案来使用Mashaller,它的子类或由工厂方法创建的自定义版本,或者可能使用链接在一起的多个Marshallers.Marshaller.withFixedContentType已经使用Accept标题所以必须有一个方法.我添加了额外奖励来奖励特定挑战的解决方案.我是黑客和变通办法,我问了这个问题,因为我需要一个解决特定方案的干净解决方案.
自定义编组器部分提到了Marshaller.oneOf重载方法,这似乎就是您想要的:
用于从多个“子编组器”创建“超级编组器”的帮助器。内容协商决定了最终由哪个“子编组器”来完成这项工作。
Marshaller伴随对象有许多接收Seq[HttpHeader]. 您也可以研究他们的实现。
我没有时间亲自研究源代码,但如果这还不足以让您走上正确的道路,请告诉我。
编辑:
怎么样?
get {
optionalHeaderValueByName("JFORMAT") { format =>
complete {
format match {
case Some(f) => "Complete with json4s"
case _ => "Complete with trueaccord"
}
}
}
}
Run Code Online (Sandbox Code Playgroud)