首页 > 解决方案 > Jersey 客户端无法反序列化 XML 输出:未找到消息正文阅读器

问题描述

我正在使用旧com.sun.jersey.jersey-client@1.19.4库在私有第三方 REST 服务上调用 POST,使用application/x-www-form-urlencoded内容类型。

一切似乎都按预期运行,但是,响应不会自动反序列化为我的 POJO。例外是 a ClientHandlerException,声称该 POJO 没有消息正文解析器。

可用的默认提供程序是:

com.sun.jersey.core.impl.provider.entity.FormProvider com.sun.jersey.core.impl.provider.entity.StringProvider com.sun.jersey.core.impl.provider.entity.ByteArrayProvider com.sun.jersey .core.impl.provider.entity.FileProvider com.sun.jersey.core.impl.provider.entity.InputStreamProvider com.sun.jersey.core.impl.provider.entity.DataSourceProvider com.sun.jersey.core.impl。 provider.entity.XMLJAXBElementProvider$General com.sun.jersey.core.impl.provider.entity.ReaderProvider com.sun.jersey.core.impl.provider.entity.DocumentProvider com.sun.jersey.core.impl.provider.entity .SourceProvider$StreamSourceReader com.sun.jersey.core.impl.provider.entity.SourceProvider$SAXSourceReader com.sun.jersey.core.impl.provider.entity.SourceProvider$DOMSourceReader com.sun.jersey.json.impl.provider。 entity.JSONJAXBElementProvider$General com.sun.jersey.json.impl.provider.entity.JSONArrayProvider$General com.sun.jersey.json.impl.provider.entity.JSONObjectProvider$General com.sun.jersey.core.impl.provider.entity.XMLRootElementProvider$General com.sun .jersey.core.impl.provider.entity.XMLListElementProvider$General com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General com.sun.jersey.core.impl.provider.entity.EntityHolderReader com.sun。 jersey.json.impl.provider.entity.JSONRootElementProvider$General com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General com.sun.jersey.json.impl.provider.entity.JacksonProviderProxyentity.XMLListElementProvider$General com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General com.sun.jersey.core.impl.provider.entity.EntityHolderReader com.sun.jersey.json.impl.provider.entity .JSONRootElementProvider$General com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General com.sun.jersey.json.impl.provider.entity.JacksonProviderProxyentity.XMLListElementProvider$General com.sun.jersey.core.impl.provider.entity.XMLRootObjectProvider$General com.sun.jersey.core.impl.provider.entity.EntityHolderReader com.sun.jersey.json.impl.provider.entity .JSONRootElementProvider$General com.sun.jersey.json.impl.provider.entity.JSONListElementProvider$General com.sun.jersey.json.impl.provider.entity.JacksonProviderProxy

预期的第三方服务 XML 输出模板:

<foobar>
    <foo>Foooooooo</foo>
    <bar>Barrrrrrr</bar>
</foobar>

POJO:

@XmlRootElement(name = "foobar")
@XmlAccessorType(XmlAccessType.FIELD)
public class Foobar {

    @XmlElement(name = "foo")
    private String foo;

    @XmlElement(name = "bar")
    private String bar;

    public String getFoo() {
        return foo;
    }

    public void setFoo(String foo) {
        this.foo = foo;
    }

    public String getBar() {
        return bar;
    }

    public void setBar(String bar) {
        this.bar = bar;
    }

}

请求:

MultivaluedMap parameters = new MultivaluedMapImpl();

parameters.add(...);

Foobar response = client.resource(URL)
        .type(MediaType.APPLICATION_FORM_URLENCODED)
        .accept(MediaType.APPLICATION_XML)
        .post(Foobar.class, parameters);

例外:

线程“主”com.sun.jersey.api.client.ClientHandlerException 中的异常:Java 类 foo.bar.Foobar、Java 类型类 foo.bar.Foobar 和 MIME 媒体类型 text/html 的消息体阅读器;在 com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:586) 的 com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:630) 中找不到 charset=UTF-8在 com.sun.jersey.api.client.WebResource.handle(WebResource.java:686) 在 com.sun.jersey.api.client.WebResource.access $200(WebResource.java:74) 在 com.sun.jersey。 api.client.WebResource$Builder.post(WebResource.java:570) at foo.bar.Main.jerseySample(Main.java:103) at foo.bar.Main.main(Main.java:109)

使用 JAXB unmarshaller 反序列化 XML 字符串可以正常工作,但是 Jersey 不能自己完成(也许借助XMLJAXBElementProvider, XMLRootElementProvider, XMLRootObjectProvider?)。这里发生了什么?

标签: javaxmlspringrestjersey

解决方案


我发现解决此问题的最简洁方法是创建一个自定义MessageBodyReader.

public static class FoobarMessageBodyReader implements MessageBodyReader<Foobar> {

    private Unmarshaller unmarshaller;

    public RespostaIncluirMessageBodyReader() throws JAXBException {
        unmarshaller = JAXBContext.newInstance(Foobar.class).createUnmarshaller();
    }

    @Override
    public boolean isReadable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType) {
        return type.isAssignableFrom(Foobar.class);
    }

    @Override
    public Foobar readFrom(Class<Foobar> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String, String> httpHeaders, InputStream entityStream) throws IOException, WebApplicationException {
        try {
            return (Foobar) unmarshaller.unmarshal(entityStream);
        }
        catch (JAXBException e) {
            throw new IOException("Could not unmarshal the XML output", e);
        }
    }

}

...并将其添加到客户端配置中,如下所示:

ClientConfig clientConfig = new DefaultClientConfig();
clientConfig.getClasses().add(FoobarMessageBodyReader.class);
Client client = Client.create(clientConfig);

您现在应该已成功反序列化您的对象。


推荐阅读