问题描述
我正在尝试解组的单元素 JSON 数组:
A one-element JSON array that I'm trying to unmarshal:
[
{
"id":"42",
"status":"Active",
"name":"purple monkey dishwasher"
}
]
对应的 Java 类(为简洁起见,省略了 getter 和 setter):
The corresponding Java class (getters & setters omitted for brevity):
@XmlRootElement
@XmlAccessorType(XmlAccessType.FIELD)
public class Badge
{
@XmlElement(name="id")
private String id;
@XmlElement(name="status")
private Status status;
@XmlElement(name="name")
private String name;
public static enum Status
{
Active,
NotActive
}
}
发出 HTTP 请求的 Jersey 客户端代码应该将上述 JSON 解组为单元素 List<Foo>
:
The Jersey Client code which makes an HTTP request and is supposed to unmarshal the above JSON into a one-element List<Foo>
:
Client client = Client.create();
WebResource apiRoot = client.resource("http://localhost:9000/api");
List<Badge> badges = apiRoot.path("/badges").get(new GenericType<List<Badge>>(){});
最后一行,特别是 WebResource#get()
调用,抛出以下异常:
The last line, specifically the WebResource#get()
call, throws the following exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"status"). Expected elements are <{}badge>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:662)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:258)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:253)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:120)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1063)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:498)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:480)
at com.sun.xml.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:75)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:247)
at com.sun.xml.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:181)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:369)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:341)
at com.sun.jersey.core.provider.jaxb.AbstractListElementProvider.readFrom(AbstractListElementProvider.java:232)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:552)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:522)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:617)
at com.sun.jersey.api.client.WebResource.get(WebResource.java:191)
at com.redacted.badge.client.BadgerImpl.findAllBadges(BadgerImpl.java:105)
at com.redacted.webapp.admin.BadgeAction.unspecified(BadgeAction.java:40)
at org.apache.struts.actions.DispatchAction.dispatchMethod(DispatchAction.java:245)
at org.apache.struts.actions.DispatchAction.execute(DispatchAction.java:170)
at org.apache.struts.chain.commands.servlet.ExecuteAction.execute(ExecuteAction.java:58)
at org.apache.struts.chain.commands.AbstractExecuteAction.execute(AbstractExecuteAction.java:67)
at org.apache.struts.chain.commands.ActionCommandBase.execute(ActionCommandBase.java:51)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.commons.chain.generic.LookupCommand.execute(LookupCommand.java:304)
at org.apache.commons.chain.impl.ChainBase.execute(ChainBase.java:190)
at org.apache.struts.chain.ComposableRequestProcessor.process(ComposableRequestProcessor.java:283)
at org.apache.struts.action.ActionServlet.process(ActionServlet.java:1913)
at org.apache.struts.action.ActionServlet.doGet(ActionServlet.java:449)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:617)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.opensymphony.module.sitemesh.filter.PageFilter.parsePage(PageFilter.java:119)
at com.opensymphony.module.sitemesh.filter.PageFilter.doFilter(PageFilter.java:55)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.MemberFilter.doFilter(MemberFilter.java:83)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.AuthFilter.doFilter(AuthFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.displaytag.filter.ResponseOverrideFilter.doFilter(ResponseOverrideFilter.java:125)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.LanguageHandlingFilter.doFilter(LanguageHandlingFilter.java:151)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:146)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.PartnerFilter.doFilter(PartnerFilter.java:59)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at com.redacted.webapp.filter.SessionStatusFilter.doFilter(SessionStatusFilter.java:113)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:470)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127)
at com.googlecode.psiprobe.Tomcat60AgentValve.invoke(Tomcat60AgentValve.java:30)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:298)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:859)
at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:588)
at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:489)
at java.lang.Thread.run(Thread.java:680)
我在 Badge
上尝试了各种注释组合,或者使用数组代替 GenericType
:
I've tried a variety of combinations of annotations on Badge
, or using an array instead of GenericType
:
List<Badge> badges = Arrays.asList(apiRoot.path("/badges").get(Badge[].class));
或使用中间ClientResponse
:
GenericType<List<Badge>> type = new GenericType<List<Badge>>(){};
ClientResponse clientResponse = apiRoot.path("/badges").get(ClientResponse.class);
List<Badge> badges = clientResponse.getEntity(type);
但目前还没有解决问题.
but none so far have solved the problem.
更令人困惑的是,我现有的设置没有问题解组其他结构内的 JSON 编码 Badge
,如下所示:
Even more confounding is the fact that my existing setup has no problems unmarshalling JSON-encoded Badge
s which are inside of other structures, like this:
{
"userid":"123456789",
"userbadges":[
{
"badge":{
"id":"42",
"status":"Active",
"name":"purple monkey dishwasher"
},
"earned":"2012-03-06 18:16:18.172"
}
]
}
我做错了什么?
推荐答案
我能够通过使用 JacksonJsonProvider
作为 Jersey 客户端的 MessageBody(Reader|Writer)
提供程序实例:
I was able to solve this with minimal effort by using JacksonJsonProvider
as the MessageBody(Reader|Writer)
provider for the Jersey Client instance:
ClientConfig cfg = new DefaultClientConfig();
cfg.getClasses().add(JacksonJsonProvider.class);
Client client = Client.create(cfg);
Jackson 的 MessageBodyReader
实现似乎比 Jersey JSON 实现更好.
Jackson's MessageBodyReader
implementation appears to be more well-behaved than the Jersey JSON one.
感谢 如何自定义将 JAXB 对象列表序列化为 JSON? 为我指明杰克逊方向.
Thanks to How can I customize serialization of a list of JAXB objects to JSON? for pointing me in the Jackson direction.
这篇关于无法使用 Jersey 客户端解组 JSON 对象数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!