1
votes

I'm using JAXB to marshall and unmarshall requests and responses to a web service I'm implementing a Java client for. I am however stuck on the following response that I need to unmarshall.

<ResultCollection xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
    <FailedItems xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
        <a:KeyValueOflongstring>
            <a:Key>12345</a:Key>
            <a:Value>Some clever message here</a:Value>
        </a:KeyValueOflongstring>
    </FailedItems>
    <SucceededItems xmlns:a="http://schemas.microsoft.com/2003/10/Serialization/Arrays"/>
</ResultCollection>

To represent the response as Java objects, I have the following domain classes:

@XmlRootElement(name="ResultCollection")
public class ResultCollectionResponse
{
    @XmlElementWrapper(name="FailedItems", namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")
    @XmlElement(name = "KeyValueOflongstring")
    public List<KeyValueOflongstring> FailedItems = new ArrayList<KeyValueOflongstring>();

    @XmlElementWrapper(name="SucceededItems", namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")
    @XmlElement(name = "long")
    public List<Long> SucceededItems = new ArrayList<Long>();
}

public class KeyValueOflongstring
{
    public Long Key;
    public String Value;
}

I'm then doing the following to unmarshal:

JAXBContext jc = JAXBContext.newInstance(ResultCollectionResponse.class);
Unmarshaller u = jc.createUnmarshaller();

// inputStream holds the XML content from the web service
ResultCollectionResponse response = (ResultCollectionResponse)u.unmarshal(inputStream);

The unmarshalling happens without incident. The ResultCollectionResponse object is created with two lists. SucceededItems is empty and FailedItems has one item. However, Key and Value on that item is null. I'm thinking this has to do with XML namespaces, but I can't for the life of me figure out how to fix it.

I tried going the other way so to speak by creating dummy objects in Java code and marshalling them into XML. When I do that, I end up with the following XML:

<ResultCollection xmlns:ns2="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
    <FailedItems>
        <ns2:KeyValueOflongstring>
            <Key>12345678</Key>
            <Value>Some clever message here</Value>
        </ns2:KeyValueOflongstring>
    </FailedItems>
    <SucceededItems/>
</ResultCollection>

As you can see, the namespace has been applied to the top level element rather than the FailedItems and SucceededItems elements. I don't understand why that is. Also, as you can see, I don't have the http://www.w3.org/2001/XMLSchema-instance namespace on the top level element because if I do, the unmarshalling fails with the exception unexpected element (uri:"", local:"ResultCollection"). Expected elements are <{http://www.w3.org/2001/XMLSchema-instance}ResultCollection>. This error message confuses me even further because the response XML clearly has said namespace.

I don't usually work with Java and XML namespaces is something that I have always kind of tried to ignore. Any help would be appreciated.

2

2 Answers

1
votes

IMO you could use the xjc tool to generate the Java classes from the XML schema automatically. It is a better guarantee that they will work with the XML schema than if you create the classes manually. Xjc is part of the JDK.

1
votes

You could do the following. In your example it is the elements with the prefix that are namespace qualfied, not the elements that contain the namespace declaration.

@XmlRootElement(name="ResultCollection")
public class ResultCollectionResponse
{
    @XmlElementWrapper(name="FailedItems")
    @XmlElement(name = "KeyValueOflongstring", namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")
    public List<KeyValueOflongstring> FailedItems = new ArrayList<KeyValueOflongstring>();

    @XmlElementWrapper(name="SucceededItems")
    @XmlElement(name = "long")
    public List<Long> SucceededItems = new ArrayList<Long>();
}
public class KeyValueOflongstring
{
    @XmlElement(namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")
    public Long Key;

    @XmlElement(namespace="http://schemas.microsoft.com/2003/10/Serialization/Arrays")
    public String Value;
}