1

我为地球上的 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)
        }
      }
    }
  }
}
4

1 回答 1

1

如果您要提供 REST 接口,最好的方法是根据路径请求的扩展名简单地确定类型,.json或者.xml. 这样,您的 API 将更易于使用。HTTP/1.1 Accept 标头文档显示内容协商有点复杂。

回答您的问题,Spray 支持基本级别的内容协商。该类HttpMessage包含一个方法,该方法isMediaTypeAccepted也被同一类中的许多其他方法使用。

当然HttpMessage,在请求和响应端也会重复使用。希望这会为您指明正确的方向。

于 2013-10-15T20:42:52.520 回答