Java – JAXB unmarshalling error

javajaxbunmarshalling

I'm using JAXB to in a Java app I'm writing. I've compiled the OCI schema into classes successfully, and I'm able to marshal an AuthenticationRequest type into XML (inside an OCIMessage), send it across and get a response back. When I try to unmarshal the response into an OCIMessage, however, it fails silently. Here's the contents of my test class:

package com.some.domain.ignore;

import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.helpers.DefaultValidationEventHandler;
import javax.xml.stream.FactoryConfigurationError;
import javax.xml.stream.XMLStreamException;
import javax.xml.transform.stream.StreamSource;

import com.some.domain.oci.OCIMessage;
import com.some.domain.oci.ObjectFactory;
import com.some.domain.schema.AuthenticationRequest;
import com.some.domain.schema.AuthenticationResponse;

public class JavaTest {
    private final static String HOST = "some.host.com";
    private final static int PORT = 2208;
    private final static String USER = "SOME_USER";

    private final static String SESSION = Long.toString(System.currentTimeMillis());
    private static Socket sock;
    private static OutputStream out;
    private static Marshaller marshaller;
    private static Unmarshaller unmarshaller;
    private static JAXBContext context;
    private static ObjectFactory factory;

    public static void main(String[] args) {
        try {
            runIt();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private static void runIt() throws XMLStreamException, FactoryConfigurationError, IOException, JAXBException {
        sock = new Socket(HOST, PORT);
        out = sock.getOutputStream();

        AuthenticationRequest request = new AuthenticationRequest();
        request.setUserId(USER);

        factory = new ObjectFactory();
        OCIMessage message = new OCIMessage();
        message.setSessionId(SESSION);
        message.setProtocol("OCI");
        message.getCommand().add(request);
        JAXBElement<OCIMessage> element = factory.createBroadsoftDocument(message);

        context = JAXBContext.newInstance(ObjectFactory.class);
        marshaller = context.createMarshaller();
        unmarshaller = context.createUnmarshaller();
        marshaller.marshal(element, out);

        unmarshaller.setEventHandler(new DefaultValidationEventHandler());
        StreamSource s = new StreamSource(sock.getInputStream());
        JAXBElement<OCIMessage> doc = unmarshaller.unmarshal(s, OCIMessage.class);
        OCIMessage response = doc.getValue();
    }
}

The actual XML response is this:

<BroadsoftDocument protocol="OCI" xmlns="C" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<sessionId xmlns="">1329428955041</sessionId>
<command echo="" xsi:type="AuthenticationResponse" xmlns="">
<userId>SOME_USER</userId>
<nonce>1329428959587</nonce>
<passwordAlgorithm>MD5</passwordAlgorithm></command>
</BroadsoftDocument>

The unmarshalling attempt fails with no error whatsoever, which is tremendously unhelpful. It's as though something inside JAXB unmarshalling code is swallowing the exception, even though I'm explicitly specifying an unmarshalling ValidationEventHandler.

Any ideas as to why this is happening? I can provide more code or information if needed.

For further reference, here is the OCIMessage class:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2012.02.13 at 03:15:18 PM EST 
//


package com.some.domain.oci.schema;

import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSchemaType;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;


/**
 * 
 *         A message contains a list of requests or responses. The server processes all the requests
 *         and returns a message with a corresponding list of responses.
 *       
 * 
 * <p>Java class for OCIMessage complex type.
 * 
 * <p>The following schema fragment specifies the expected content contained within this class.
 * 
 * <pre>
 * &lt;complexType name="OCIMessage">
 *   &lt;complexContent>
 *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
 *       &lt;sequence>
 *         &lt;choice>
 *           &lt;element name="sessionId" type="{http://www.w3.org/2001/XMLSchema}normalizedString"/>
 *           &lt;element name="userId" type="{http://www.w3.org/2001/XMLSchema}token"/>
 *           &lt;element name="phoneNumber" type="{http://www.w3.org/2001/XMLSchema}token"/>
 *         &lt;/choice>
 *         &lt;element name="command" type="{C}OCICommand" maxOccurs="15"/>
 *       &lt;/sequence>
 *       &lt;attribute name="protocol" use="required">
 *         &lt;simpleType>
 *           &lt;restriction base="{http://www.w3.org/2001/XMLSchema}NMTOKEN">
 *             &lt;enumeration value="OCI"/>
 *             &lt;enumeration value="NSOCI"/>
 *           &lt;/restriction>
 *         &lt;/simpleType>
 *       &lt;/attribute>
 *     &lt;/restriction>
 *   &lt;/complexContent>
 * &lt;/complexType>
 * </pre>
 * 
 * 
 */
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "OCIMessage", propOrder = {
    "sessionId",
    "userId",
    "phoneNumber",
    "command"
})
public class OCIMessage {

    @XmlJavaTypeAdapter(NormalizedStringAdapter.class)
    @XmlSchemaType(name = "normalizedString")
    protected String sessionId;
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "token")
    protected String userId;
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    @XmlSchemaType(name = "token")
    protected String phoneNumber;
    @XmlElement(required = true)
    protected List<OCICommand> command;
    @XmlAttribute(name = "protocol", required = true)
    @XmlJavaTypeAdapter(CollapsedStringAdapter.class)
    protected String protocol;

    /**
     * Gets the value of the sessionId property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getSessionId() {
        return sessionId;
    }

    /**
     * Sets the value of the sessionId property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setSessionId(String value) {
        this.sessionId = value;
    }

    /**
     * Gets the value of the userId property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getUserId() {
        return userId;
    }

    /**
     * Sets the value of the userId property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setUserId(String value) {
        this.userId = value;
    }

    /**
     * Gets the value of the phoneNumber property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getPhoneNumber() {
        return phoneNumber;
    }

    /**
     * Sets the value of the phoneNumber property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setPhoneNumber(String value) {
        this.phoneNumber = value;
    }

    /**
     * Gets the value of the command property.
     * 
     * <p>
     * This accessor method returns a reference to the live list,
     * not a snapshot. Therefore any modification you make to the
     * returned list will be present inside the JAXB object.
     * This is why there is not a <CODE>set</CODE> method for the command property.
     * 
     * <p>
     * For example, to add a new item, do as follows:
     * <pre>
     *    getCommand().add(newItem);
     * </pre>
     * 
     * 
     * <p>
     * Objects of the following type(s) are allowed in the list
     * {@link OCICommand }
     * 
     * 
     */
    public List<OCICommand> getCommand() {
        if (command == null) {
            command = new ArrayList<OCICommand>();
        }
        return this.command;
    }

    /**
     * Gets the value of the protocol property.
     * 
     * @return
     *     possible object is
     *     {@link String }
     *     
     */
    public String getProtocol() {
        return protocol;
    }

    /**
     * Sets the value of the protocol property.
     * 
     * @param value
     *     allowed object is
     *     {@link String }
     *     
     */
    public void setProtocol(String value) {
        this.protocol = value;
    }

}

Lastly, here's the contents of ObjectFactory, which is responsible for creating a BroadsoftDocument, via the createBroadsoftDocument method:

//
// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, v2.2.4 
// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
// Any modifications to this file will be lost upon recompilation of the source schema. 
// Generated on: 2012.02.13 at 03:15:18 PM EST 
//


package com.some.domain.oci;

import javax.xml.bind.JAXBElement;
import javax.xml.bind.annotation.XmlElementDecl;
import javax.xml.bind.annotation.XmlRegistry;
import javax.xml.namespace.QName;


/**
 * This object contains factory methods for each 
 * Java content interface and Java element interface 
 * generated in the c package. 
 * <p>An ObjectFactory allows you to programatically 
 * construct new instances of the Java representation 
 * for XML content. The Java representation of XML 
 * content can consist of schema derived interfaces 
 * and classes representing the binding of schema 
 * type definitions, element declarations and model 
 * groups.  Factory methods for each of these are 
 * provided in this class.
 * 
 */
@XmlRegistry
public class ObjectFactory {

    private final static QName _BroadsoftDocument_QNAME = new QName("C", "BroadsoftDocument");

    /**
     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: c
     * 
     */
    public ObjectFactory() {
    }

    /**
     * Create an instance of {@link OCIMessage }
     * 
     */
    public OCIMessage createOCIMessage() {
        return new OCIMessage();
    }

    /**
     * Create an instance of {@link SuccessResponse }
     * 
     */
    public SuccessResponse createSuccessResponse() {
        return new SuccessResponse();
    }

    /**
     * Create an instance of {@link OCITableRow }
     * 
     */
    public OCITableRow createOCITableRow() {
        return new OCITableRow();
    }

    /**
     * Create an instance of {@link ErrorResponse }
     * 
     */
    public ErrorResponse createErrorResponse() {
        return new ErrorResponse();
    }

    /**
     * Create an instance of {@link OCITable }
     * 
     */
    public OCITable createOCITable() {
        return new OCITable();
    }

    /**
     * Create an instance of {@link JAXBElement }{@code <}{@link OCIMessage }{@code >}}
     * 
     */
    @XmlElementDecl(namespace = "C", name = "BroadsoftDocument")
    public JAXBElement<OCIMessage> createBroadsoftDocument(OCIMessage value) {
        return new JAXBElement<OCIMessage>(_BroadsoftDocument_QNAME, OCIMessage.class, null, value);
    }

}

Best Answer

Looks like a mapping error: The response XML Document contains the sessionId element and the mapping of AuthenticationResponse type isn't prepared for it. If you post the class (including mapping annotations) we can help you more.

Related Topic