Jersey:阅读内容类型:简单/文本响应为XML

时间:2016-11-17 15:29:30

标签: java xml jaxb jersey mime-types

我从正文中包含HTTP的外部服务器收到XML响应。

但是,响应标题显示为Content-Type:plain/text

这是不正确的,应该是application/xml。但是,正如我所说,它是一个我们无法改变的外部服务器。

以下代码给出错误:

ClientResponse response = Client.create().resource(url).get(ClientResponse.class);
return response.getEntity(XmlResponse.class);

例外:

  

com.sun.jersey.api.client.ClientHandlerException:邮件正文   reader for com class com.evs.ats.XmlResponse和Java type class   com.evs.ats.XmlResponse,找不到MIME媒体类型text / plain

以下代码有效,但我不喜欢它:

String resultString = response.getEntity(String.class);
InputStream stream = new ByteArrayInputStream(
    resultString.getBytes(StandardCharsets.UTF_8)
);
JAXBContext jc = JAXBContext.newInstance(XmlResponse.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
return (XmlResponse) unmarshaller.unmarshal(stream);

有没有办法强迫"强迫"无论如何,泽西岛将其视为XML?或者是我唯一可以使用JAXB手动解组它(如上所述)?或者还有其他选择吗?

1 个答案:

答案 0 :(得分:0)

如果您连接的上游服务器在Content-Type HTTP标头字段中返回错误的值,并且无法“推理”(以修复返回的值),则没有其他方法(AFAIK)除了提供您自己的MessageBodyReader的自定义实现。

使用泽西2 进行此操作的一种方法是:

public class TextAsXmlMessageBodyReader implements MessageBodyReader<Object> {

    @Override
    public boolean isReadable(Class<?> type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return mediaType.getType().equals("text")
                && mediaType.getSubtype().equals("plain");
    }

    @Override
    public Object readFrom(Class<Object> type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap<String, String> httpHeaders,
            InputStream entityStream) throws IOException, WebApplicationException {
        try {
            final JAXBContext jc = JAXBContext.newInstance(type);
            final Unmarshaller unmarshaller = jc.createUnmarshaller();

            return unmarshaller.unmarshal(entityStream);
        } catch (JAXBException e) {
            throw new WebApplicationException("Error while unmarshalling the response.", e);
        }
    }
}

然后只需在您正在使用的Jersey客户端注册此课程。如果您在整个应用程序中使用相同的客户端实例,则可以为每个目标注册自定义消息体读取器(因此,如果您碰巧有其他上游服务器,则不会将其用于其他“理智”服务器的响应)你正在与之交流)。注册目标的示例:

return ClientBuilder.newClient()  // Get a client; does not have to be a *new* client
        .target(url)              // Target the client to the particular upstream URL
        .register(TextAsXmlMessageBodyReader.class)  // Register the reader as described
        .request()                // Start building a request
        .get(XmlResponse.class);  // Issue a GET request (can be any HTTP method actually)

拥有自定义阅读器实现的优势在于,可以编写精简的简化代码,专注于配置和发出请求,获取响应以及在需要时进行处理。此外,如果您需要针对目标服务器上的不同资源发出请求(并且所有资源都指定了错误的Content-Type),则可以重用读者实现。