我为地球上的json数据编写了最丑陋的Marshaller。尽管它很可怕,它仍然有效。问题是,当我添加代码来编组xml时,它只会封送xml并退出接受json。有人能举个例子说明一个更好的方法吗?我只是希望能够根据提供的ACCEPT标头将我的对象编组并解组为xml和json。
trait StupidFormats extends DefaultJsonProtocol with SprayJsonSupport with MetaMarshallers {
val formatter: DateTimeFormatter = DateTimeFormat.forPattern("MM/dd/yyyy HH:mm:ss ZZZ").withLocale(
Locale.ROOT).withChronology(ISOChronology.getInstanceUTC)
val periodFormatter: PeriodFormatter = new PeriodFormatterBuilder().printZeroAlways().minimumPrintedDigits(1)
.appendDays().appendSuffix(" days").appendSeparator(", ").printZeroAlways().minimumPrintedDigits(2).appendHours()
.appendSeparator(":").printZeroAlways().minimumPrintedDigits(2).appendMinutes().appendSeparator(":").appendSeconds()
.toFormatter
/*implicit val dataResultXmlMarshaller: Marshaller[DataResult] =
Marshaller.delegate[DataResult, NodeSeq](`text/xml`, `application/xml`, `text/html`, `application/xhtml+xml`)
{ d: DataResult =>
<DataResult>
<ApplicationVersion>{d.applicationVersion}</ApplicationVersion>
<Datestamp>{d.dateStamp}</Datestamp>
<IsHealthy>{d.isHealthy}</IsHealthy>
<MemFree>{d.memFree}</MemFree>
<MemMax>{d.memMax}</MemMax>
<MemPeak>{d.memPeak}</MemPeak>
<MemUsed>{d.memUsed}</MemUsed>
<ServiceHostIp>{d.serviceHostIp}</ServiceHostIp>
<Uptime>{periodFormatter.print(d.uptime)}</Uptime>
<OptionalElements></OptionalElements>
</DataResult>
}*/
implicit object DataResultJsonFormat extends RootJsonFormat[DataResult] {
def write(d: DataResult) = {
JsObject(
"ApplicationVersion" -> JsString(d.applicationVersion),
"Datestamp" -> JsNumber(d.dateStamp),
"IsHealthy" -> JsBoolean(d.isHealthy),
"MemFree" -> JsNumber(d.memFree),
"MemMax" -> JsNumber(d.memMax),
"MemPeak" -> JsNumber(d.memPeak),
"MemUsed" -> JsNumber(d.memUsed),
"ServiceHostIp" -> JsString(d.serviceHostIp),
"Uptime" -> JsString(periodFormatter.print(d.uptime)),
"OptionalElements" -> JsObject (
"OptionalElement" -> (
for (oe <- d.optionalElements if d.optionalElements.size > 0) yield {
JsObject (
"DataType" -> JsString(oe.dataType),
"Description" -> JsString(oe.description),
"LastUpdated" -> JsString(formatter.print(oe.lastUpdated)),
"Name" -> JsString(oe.name),
"Value" -> JsString(oe.value)
)
}
).collect { case v: JsObject => v.fields }.toJson
)
)
}
def read(js: JsValue) = {
js.asJsObject.getFields("ApplicationVersion", "DateStamp", "IsHealthy", "MemFree", "MemMax", "MemPeak",
"MemUsed", "ServiceHostIP", "Uptime", "OptionalElement") match {
case Seq(
JsString(applicationVersion),
JsNumber(dateStamp),
JsBoolean(isHealthy),
JsNumber(memFree),
JsNumber(memMax),
JsNumber(memPeak),
JsNumber(memUsed),
JsString(serviceHostIp),
JsString(uptime),
JsArray(optionalElements)
) => { DataResult (
applicationVersion,
dateStamp.toLong,
isHealthy,
memFree.toLong,
memMax.toLong,
memPeak.toLong,
memUsed.toLong,
serviceHostIp,
Period.parse(uptime, periodFormatter),
(for (oe <- optionalElements if optionalElements.size > 0) yield {
oe.asJsObject.getFields("DataType", "Description", "LastUpdated", "Name", "Value") match {
case Seq(
JsString(dataType),
JsString(description),
JsString(lastUpdated),
JsString(name),
JsString(value)
) => OptionalElement (
dataType,
description,
DateTime.parse(lastUpdated, formatter),
name, value)
}
}).toList)
}
}
}
}
}
答案 0 :(得分:1)
如果您要提供REST界面,最好的方法是根据路径请求的扩展名.json
或.xml
来确定类型。这样您的API将更容易使用。 HTTP/1.1 Accept header documentation表明内容协商有点复杂。
回答您的问题,Spray支持基本级别的内容协商。 HttpMessage
类包含一个方法isMediaTypeAccepted
,该方法也被同一类中的许多其他方法使用。
当然HttpMessage
也会在请求和响应方面重复使用。希望这能指明你的正确方向。