Jersey 客户端无法反序列化 XML 输出:未找到消息正文 reader
Jersey client can't deserialize the XML output: message body reader was not found
我正在使用旧的 com.sun.jersey.jersey-client@1.19.4
库在私人第三方 REST 服务上调用 POST,使用 application/x-www-form-urlencoded
内容类型。
一切似乎都按预期运行,但是,响应不会自动反序列化到我的 POJO。例外是 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.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);
异常:
Exception in thread "main"
com.sun.jersey.api.client.ClientHandlerException: A message body
reader for Java class foo.bar.Foobar, and Java type class
foo.bar.Foobar, and MIME media type text/html; charset=UTF-8 was not
found at
com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:630)
at
com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:586)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686)
at
com.sun.jersey.api.client.WebResource.access0(WebResource.java:74)
at
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 解组器反序列化 XML 字符串工作得很好,但是 Jersey 不能自己完成(可能在 XMLJAXBElementProvider
、XMLRootElementProvider
的帮助下) XMLRootObjectProvider
?)。这是怎么回事?
我发现解决这个问题的最干净的方法是创建自定义 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);
您现在应该已成功反序列化您的对象。
我正在使用旧的 com.sun.jersey.jersey-client@1.19.4
库在私人第三方 REST 服务上调用 POST,使用 application/x-www-form-urlencoded
内容类型。
一切似乎都按预期运行,但是,响应不会自动反序列化到我的 POJO。例外是 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.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);
异常:
Exception in thread "main" com.sun.jersey.api.client.ClientHandlerException: A message body reader for Java class foo.bar.Foobar, and Java type class foo.bar.Foobar, and MIME media type text/html; charset=UTF-8 was not found at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:630) at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:586) at com.sun.jersey.api.client.WebResource.handle(WebResource.java:686) at com.sun.jersey.api.client.WebResource.access0(WebResource.java:74) at 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 解组器反序列化 XML 字符串工作得很好,但是 Jersey 不能自己完成(可能在 XMLJAXBElementProvider
、XMLRootElementProvider
的帮助下) XMLRootObjectProvider
?)。这是怎么回事?
我发现解决这个问题的最干净的方法是创建自定义 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);
您现在应该已成功反序列化您的对象。