我的应用支持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)
}
})
我想对我使用Marshaller.oneOf和JSON处理的Marshaller做同样的事情:
Marshaller.withFixedContentType(contentType) { value =>
val jsonText = JsonSerializer.toJsonString[T](value)
HttpEntity(contentType, jsonText)
}
有没有办法构建一个知道请求http头的Mashaller? Akka HTTP文档没有任何示例,我无法理解PredefinedToRequestMarshallers。
我是否需要以某种方式组合多个marshallers,或者我可以在请求序列化期间将一些元数据附加到上下文中,我可以稍后在Marshaller中使用它?如果可能,我想避免将meta附加到我的dto或使用自定义内容类型,如application/vnd.api+json
当我将响应格式化为Accept-Encoding时,我可以从请求中使用许多其他有用的信息,自定义标头(如唯一请求ID)来创建相关ID,我可以通过阅读{{1}来添加JSONP支持} query parmeter等。
澄清:我需要一个解决方案来使用Mashaller,它的子类或由工厂方法创建的自定义版本,或者可能是多个Marshallers链接在一起。 callback
已使用Marshaller.withFixedContentType
标题,因此必须有办法。我添加了额外奖励来奖励特定挑战的解决方案。我是黑客和变通办法,我问了这个问题,因为我需要一个解决特定方案的干净解决方案。
答案 0 :(得分:0)
Custom Marshallers部分提到Marshaller.oneOf
重载方法,这似乎是您想要的:
帮助创建一个超级编组者"来自一些 "子marshallers&#34 ;.内容协商确定哪个 "子编组"最终得到了这份工作。
Marshaller个随播广告对象有很多接收Seq[HttpHeader]
的方法。您也可以查看他们的实现。
我没有时间自己查看源代码,但如果这还不足以让您走上正确的道路,请告诉我。
修改强>:
怎么样?
get {
optionalHeaderValueByName("JFORMAT") { format =>
complete {
format match {
case Some(f) => "Complete with json4s"
case _ => "Complete with trueaccord"
}
}
}
}