Hello,
I'm having trouble unmarshalling some JSON back into the desired type using a XmlAdapter. In particular I'm marshalling a java.util.Map into JSON on the server side. So far it works fine. The unmarshalling on the client side gives me the following stack trace:
Exception in thread "main" javax.ws.rs.WebApplicationException: javax.xml.bind.UnmarshalException
- with linked exception:
[java.lang.NullPointerException]
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:113)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:553)
at com.sun.jersey.api.client.ClientResponse.getEntity(ClientResponse.java:506)
at com.sun.jersey.api.client.WebResource.handle(WebResource.java:674)
at com.sun.jersey.api.client.WebResource.access$200(WebResource.java:74)
at com.sun.jersey.api.client.WebResource$Builder.get(WebResource.java:503)
at test.JerseyClient.main(JerseyClient.java:113)
Caused by: javax.xml.bind.UnmarshalException
- with linked exception:
[java.lang.NullPointerException]
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.handleStreamException(UnmarshallerImpl.java:414)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:351)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:328)
at com.sun.jersey.json.impl.BaseJSONUnmarshaller.unmarshalJAXBElementFromJSON(BaseJSONUnmarshaller.java:108)
at com.sun.jersey.json.impl.BaseJSONUnmarshaller.unmarshalFromJSON(BaseJSONUnmarshaller.java:97)
at com.sun.jersey.json.impl.provider.entity.JSONRootElementProvider.readFrom(JSONRootElementProvider.java:125)
at com.sun.jersey.core.provider.jaxb.AbstractRootElementProvider.readFrom(AbstractRootElementProvider.java:111)
... 6 more
Caused by: java.lang.NullPointerException
at org.apache.xml.utils.DOMBuilder.startElement(DOMBuilder.java:322)
at org.apache.xalan.transformer.TransformerIdentityImpl.startElement(TransformerIdentityImpl.java:1020)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.DomLoader.startElement(DomLoader.java:107)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiTypeLoader.startElement(XsiTypeLoader.java:62)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:470)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:448)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.InterningXmlVisitor.startElement(InterningXmlVisitor.java:60)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector.handleStartElement(StAXStreamConnector.java:231)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.StAXStreamConnector.bridge(StAXStreamConnector.java:165)
at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:349)
... 11 more
Caused by: java.lang.NullPointerException
at org.apache.xml.utils.DOMBuilder.startElement(DOMBuilder.java:289)
... 20 more
The funny thing is, that unmarshalling the data when set to XML works fine. Only JSON seems to cause problems. My Ressource looks like this:
@Path("/")
public class MyResource
{
@GET
@Path("/map")
@Produces(MediaType.APPLICATION_JSON)
public MapHolder getMap()
{
MapHolder model = new MapHolder();
model.fillMap();
return model;
}
}
@XmlRootElement(name="map-holder")
@XmlAccessorType(XmlAccessType.NONE)
public class MapHolder
{
private Map map;
public MapHolder()
{
map = new HashMap();
}
@XmlElement
@XmlJavaTypeAdapter(MapAdapter.class)
public Map getMap()
{
return map;
}
public void setMap(Map map)
{
this.map = map;
}
public void fillMap()
{
map.put(1234567890l, 0.0);
map.put(9876543210l, 1.0);
}
}
This is converted using the following XmlAdapter:
public class MapAdapter extends XmlAdapter,Map>
{
@Override
public Map unmarshal(MapBean v) throws Exception
{
Map map = new HashMap();
for(MapEntryBean entry : v.getEntry())
{
map.put(entry.getKey(), entry.getValue());
}
return map;
}
@Override
public MapBean marshal(Map v) throws Exception
{
return new MapBean(v);
}
}
@XmlRootElement(name="map")
@XmlAccessorType(XmlAccessType.NONE)
public class MapBean
{
private List> entry;
public MapBean()
{
entry = new ArrayList>();
}
public MapBean(Map map)
{
entry = new ArrayList>();
for(Map.Entry e : map.entrySet())
{
entry.add(new MapEntryBean(e));
}
}
@XmlElement
public List> getEntry()
{
return entry;
}
public void setEntry(List> entry)
{
this.entry = entry;
}
}
@XmlType(name="entry")
@XmlAccessorType(XmlAccessType.NONE)
public class MapEntryBean
{
private K key;
private V value;
public MapEntryBean()
{
}
public MapEntryBean(Map.Entry entry)
{
this.key = entry.getKey();
this.value = entry.getValue();
}
@XmlElement
public K getKey()
{
return key;
}
public void setKey(K key)
{
this.key = key;
}
@XmlElement
public V getValue()
{
return value;
}
public void setValue(V value)
{
this.value = value;
}
}
Calling the desired service inside the browser gives me the following JSON data:
{"map":{"entry":[{"key":{"@type":"xs:long","$":"9876543210"},"value":{"@type":"xs:double","$":"1.0"}},{"key":{"@type":"xs:long","$":"1234567890"},"value":{"@type":"xs:double","$":"0.0"}}]}}
The code for unmarshalling on the client side is:
MapHolder holder = webResource.path("map").accept(MediaType.APPLICATION_JSON).get(MapHolder.class);
System.out.println(holder.getMap().entrySet());
I'm probably missing something obvious but I have no clue what is causing the problem. That's why I included the whole test source code, as I don't know where things go wrong.
Any help is highly appreciated.
Thanks in advice
Chris
--
Christian Gerteis
TIT 08