【问题标题】:How to return XML based on Accept-header using (Java) Akka HTTP?如何使用(Java)Akka HTTP 基于 Accept-header 返回 XML?
【发布时间】:2017-06-28 17:27:00
【问题描述】:

我正在使用 Akka HTTP(Java 版本)来创建 REST API。我有一个返回应用程序/json 的工作概念证明。不幸的是,我找不到任何明确的文档和/或(工作)示例来说明如何使它也返回其他内容(在我的情况下:text/xml)。

这是我目前拥有的相关位(只要我发送没有 Accept 标头或带有 Accept 标头 application/json 的请求,它就会返回 Airport 对象的 JSON 表示):

return route(
  get(() -> 
    pathPrefix("reference", () -> 
      pathPrefix("v1", () -> 
        pathPrefix("airport", () -> 
          parameter("iataCode", (String iataCode) -> {
              final CompletionStage<Optional<Airport>> futureMaybeAirport = fetchAirport(iataCode);
              return onSuccess(
                () -> futureMaybeAirport
                , maybeAirport -> maybeAirport.map(airport -> 
                    completeOK(airport, Jackson.marshaller())
                  ).orElseGet(() -> 
                    complete(StatusCodes.NOT_FOUND, "Not Found")
                  )
              );
            }
          )
        )
      )
    )
  )
);

当我将 text/xml 放入 Accept 标头时,我得到一个 HTTP 406。因此,经过一些研究,似乎我必须提供自己的 Marshaller 才能输出 text/xml。知道 Akka 使用 Jackson,我想使用提供 XMLMapper 的 jackson-dataformat-xml 模块。因此,我按如下方式创建了我的自定义 Marshaller(Akka 在他们的 Jackson 课程中也是这样做的):

public static <T> Marshaller<T, RequestEntity> xmlMarshaller() {
    return Marshaller.wrapEntity(
            u -> toXML(u),
            Marshaller.stringToEntity(),
            MediaTypes.TEXT_XML
    );
}

private static String toXML(Object object) {
    try {
        return new XmlMapper().writeValueAsString(object);
    } catch (JsonProcessingException e) {
        throw new IllegalArgumentException("Cannot marshal to XML: " + object, e);
    }
}

到目前为止一切顺利,但现在是棘手的部分:我如何让 Akka HTTP 清楚我现在希望它使用默认的 JSON Marshaller 或这个 XML Marshaller?据我了解,您可以使用 Marshaller.oneOf 来做到这一点。不幸的是,在网上没有找到 oneOf 的一个实际示例(当然也没有在 Akka HTTP 的关于编组的 Java 文档中,它只是 Scala 版本的副本,并注明文档需要修复)。

我想我需要这样做:

List<Marshaller<Airport, RequestEntity>> marshallers = new ArrayList();
marshallers.add(Jackson.marshaller());
marshallers.add(xmlMarshaller());

Marshaller<Airport, RequestEntity> airportMarshaller = Marshaller.oneOf(JavaConversions.asScalaBuffer(marshallers).toSeq());

这样我就可以将我的 completeOk 调整为:

completeOK(airport, airportMarshaller)

不幸的是,我无法让 Marshaller.oneOf 工作,编译器一直在抱怨:

incompatible types: inference variable A has incompatible equality constraints Object,Airport where A,B are type-variables:
A extends Object declared in method <A,B>oneOf(Seq<Marshaller<A,B>>)
B extends Object declared in method <A,B>oneOf(Seq<Marshaller<A,B>>)

鉴于我的 A 和 B(Airport 和 RequestEntity)显然扩展了 Object(Java 中几乎所有东西都是如此),我不清楚究竟是什么问题。因此,如果您有一双新的眼睛,我们将不胜感激!

另外:我在这里假设 Akka HTTP 的内置内容协商将根据 Accept 标头中的值确定使用哪个 Marshaller。我的这个假设是正确的,还是我试图以完全错误的方式解决问题?

【问题讨论】:

    标签: java xml marshalling akka-http


    【解决方案1】:

    好的,所以我自己想通了(新的一天,一双新的眼睛;-)。

    实际上,我的问题中已经写过:

     List<Marshaller<List<Airport>, RequestEntity>> marshallers = new ArrayList();
     marshallers.add(Jackson.marshaller());
     marshallers.add(xmlMarshaller());
    
     Marshaller<List<Airport>, RequestEntity> airportMarshaller = Marshaller.oneOf(JavaConversions.asScalaBuffer(marshallers).toSeq());
    

    在 completeOK 中,它实际上是这样的:

    completeOK(airport, airportMarshaller);
    

    xmlMarshaller() 和 toXML(Object) 方法没有改变。

    所以,事实证明我走在正确的轨道上,但只是忘记了我返回 List 而不是导致编译器错误的 Airport 的事实。

    【讨论】:

      猜你喜欢
      • 2018-05-11
      • 1970-01-01
      • 1970-01-01
      • 2011-07-16
      • 1970-01-01
      • 2016-10-19
      • 1970-01-01
      • 1970-01-01
      • 2011-07-06
      相关资源
      最近更新 更多