javaxmlexceptionunmarshallingjavax

Having trouble Unmarshalling XML in Java


Here's the xml I receive

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<soap-env:Envelope xmlns:soap-env="http://schemas.xmlsoap.org/soap/envelope/">
    <soap-env:Header/>
    <soap-env:Body RequestId="1503948112779" Transaction="HotelResNotifRS">
        <OTA_HotelResNotifRS xmlns="http://www.opentravel.org/OTA/2003/05" TimeStamp="2017-08-28T19:21:54+00:00" Version="1.003">
            <Errors>
                <Error Code="450" Language="en-us" ShortText="Unable to process " Status="NotProcessed" Type="3">Discrepancy between ResGuests and GuestCounts</Error>
            </Errors>
        </OTA_HotelResNotifRS>
    </soap-env:Body>
</soap-env:Envelope>

This gets pseudo unmarshalled into an OTAHotelResNotifRS object which you can get .getErrors() on. The issue is that there was no type associated with this bit, so it comes back as an Object which is in the form of an ElementNSImpl. I don't control the OTAHotelResNotifRS object, so my best bet is to unmarshal the .getErrors() object into a pojo of my own. This is my attempt.

@XmlRootElement(name = "Errors")
@XmlAccessorType(XmlAccessType.FIELD)
public class CustomErrorsType {
    @XmlAnyElement(lax = true)
    private String[] errors;

    public String[] getErrors() {
        return errors;
    }
}

This is the code used to try to unmarshal it into my CustomErrorsType object

Object errorsType = otaHotelResNotifRS.getErrors();
JAXBContext context = JAXBContext.newInstance(CustomErrorsType.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
CustomErrorsType customErrorsType = (CustomErrorsType)unmarshaller.unmarshal((Node)errorsType);

It throws the following exception when calling unmarshal

javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.opentravel.org/OTA/2003/05", local:"Errors"). Expected elements are <{}Errors>

Any thoughts? I'm pretty weak when it comes to xml unmarshalling.


Solution

  • You are ignoring the XML namespace in the response, as defined in the xmlns attribute. See https://www.w3.org/TR/xml-names/ for a full explanation of namespaces and the attributes which define them.

    A standard notation for describing an XML name with its namespace is {namespace-uri}local-name. So the exception is literally telling you that your CustomErrorsType expects an element with the local name Errors and an empty namespace ({}), but instead it encountered an element with the local name Errors and a namespace which is http://www.opentravel.org/OTA/2003/05.

    Try changing this:

    @XmlRootElement(name = "Errors")
    

    to this:

    @XmlRootElement(name = "Errors", namespace = "http://www.opentravel.org/OTA/2003/05")
    

    As a side note, if you have access to the WSDL which defines the SOAP service, you can make your task considerably easier by invoking the standard JDK tool wsimport with the WSDL’s location as an argument. All marshalling will be implicitly taken care of by the generated Service and Port classes.