Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot unmarshal a JSON array of objects using Jersey Client

A one-element JSON array that I'm trying to unmarshal:

[    {       "id":"42",       "status":"Active",       "name":"purple monkey dishwasher"    } ] 

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     } } 

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>>(){}); 

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) 

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)); 

or using an intermediate 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.

Even more confounding is the fact that my existing setup has no problems unmarshalling JSON-encoded Badges 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"       }    ] } 

What am I doing wrong?

like image 470
Matt Ball Avatar asked Mar 09 '12 00:03

Matt Ball


1 Answers

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's MessageBodyReader implementation appears to be more well-behaved than the Jersey JSON one.

Thanks to How can I customize serialization of a list of JAXB objects to JSON? for pointing me in the Jackson direction.

like image 129
Matt Ball Avatar answered Oct 04 '22 05:10

Matt Ball