我使用Akka HTTP( Java 版本)来创建REST API' s。我有一个返回application / json的工作概念证明。不幸的是,我找不到任何明确的文档和/或(工作)示例,如何使它也返回其他东西(在我的例子中:text / xml)。
这是我目前所拥有的相关位(只要我发送没有Accept标头或Accept header 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")
)
);
}
)
)
)
)
)
);
当我在Accept头中放置text / xml时,我得到了一个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。我在这个假设中是正确的还是我试图以完全错误的方式解决问题?
答案 0 :(得分:2)
好的,所以我自己想出来了(新的一天,一双新鲜的眼睛; - )。
其实基本上已经在我的问题中写了:
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());
在完整的OK中,它实际上是这样的:
completeOK(airport, airportMarshaller);
xmlMarshaller()和toXML(Object)方法未更改。
所以,事实证明我是在正确的轨道,但只是忘记了我返回List&lt; Airport&gt;的事实。而不是导致编译器错误的机场。