XML unmarshalling using Jaxb with namespaces and schema

13,809

In general, for how to access files (XSD or others) in your Java web application (since you mentioned REST), you could start here. Never rely on absolute paths, for deployment as well as security reasons.

The xsi schema location attributes are just hints; they are not required. Even if present those don't have to be considered. For a server side application, I would never use them anyway; one should rely on embedded resources, or use a catalog-like concept at a trusted/secure location.

The fact that it doesn't unmarshal, is clear in the error message: it expects a no-namespace element <{}msgdata> as opposed to <{http://www.myCompany.com}msgdata>.

You need to modify the XML or ammend your class to include things like @XmlElement(name="...", namespace="http://www.myCompany.com")

I would say that given schema and XML are correct, your annotations are not in sync.

Share:
13,809
ziggy
Author by

ziggy

Updated on June 04, 2022

Comments

  • ziggy
    ziggy almost 2 years

    I have an XML document that looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
    <xs:msgdata xmlns:xs="http://www.myCompany.com" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xsi:schemaLocation="http://www.myCompany.com msgdata.xsd">
      <xs:msgid>MsgID001</xs:msgid>
      <xs:msgHash>hlkJKLHljkhkjlHKJLHkjl6y987HJKH</xs:msgHash> 
    </xs:msgdata>
    

    A schema document (called msgdata.xsd) was also sent to me. I am using JAXB to unmarshall the above xml document to a Java object. The unmarshalling code is shown below:

    final JAXBContext context = JAXBContext.newInstance(clazz);
    SchemaFactory sf = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
    Schema schema = sf.newSchema(new File("C:\\temp\\msgdata.xsd"));
    
    final Unmarshaller unmarshaller = context.createUnmarshaller();
    unmarshaller.setSchema(schema);
    
    return (T) unmarshaller.unmarshal(new StringReader(xml));  
    

    The target object for the XML is shown below (The object is then converted to a hibernated entity.

    @XmlRootElement(name = "msgdata")
    public class Message {
    
        private     String  msgid;
        private     String  msgHash;
    
        @XmlElement(name = "msgid")
        public String getMsgid() {
            return msgid;
        }
    
        public void setMsgid(String msgid) {
            this.msgid = msgid;
        }
    
        @XmlElement(name = "msgHash")
        public String getMsgHash() {
            return msgHash;
        }
        public void setMsgHash(String msgHash) {
            this.msgHash = msgHash;
        }
    

    A couple of questions:

    • I have a rest service where i will receive an XML document in the format shown above. What is the reference for the schema document. I know that the schema document is used for validating the XML document. I think the way it will work is that i use that schema to validate the XML documents that i receive via the REST service. Now the problem is how do i access the schema? Do i just store it somewhere on my file system and access it as shown above?

    The XML document has a reference to the schema (See the schemaLocation entry). How will it find the schema document on my file system? Is that schema reference required in the XML document?

    • The XML document as it is now cannot be unmarshalled. When i try to unmarshal it i get the following error:

      Caused by: javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.myCompany.com", local:"msgdata"). Expected elements are <{}msgdata> at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:662) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:258) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:253) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:120) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1063) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:498) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:480) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.ValidatingUnmarshaller.startElement(ValidatingUnmarshaller.java:102) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:150) [jaxb-impl-2.2.4.jar:] at org.apache.xerces.parsers.AbstractSAXParser.startElement(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.impl.XMLNSDocumentScannerImpl.scanStartElement(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.impl.XMLNSDocumentScannerImpl$NSContentDispatcher.scanRootElementHook(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl$FragmentContentDispatcher.dispatch(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.impl.XMLDocumentFragmentScannerImpl.scanDocument(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.parsers.XML11Configuration.parse(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.parsers.XMLParser.parse(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.parsers.AbstractSAXParser.parse(Unknown Source) [xercesImpl-2.9.1.jar:] at org.apache.xerces.jaxp.SAXParserImpl$JAXPSAXParser.parse(Unknown Source) [xercesImpl-2.9.1.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:217) [jaxb-impl-2.2.4.jar:] at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:189) [jaxb-impl-2.2.4.jar:] at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:136) [jboss-jaxb-api_2.2_spec-1.0.3.Final.jar:1.0.3.Final] at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:193) [jboss-jaxb-api_2.2_spec-1.0.3.Final.jar:1.0.3.Final] ... 31 more

    I thought the namespace is defined in the xml document. I am either not using the schema correctly or the namespace definition is not correct. What am i doing wrong?

    Thanks.

  • ziggy
    ziggy about 12 years
    Do i need to specify the namespace with the annotations?
  • Petru Gardea
    Petru Gardea about 12 years
    Yes, please use @ XmlElement or @ XmlRootElement with name and namespace: (name="...", namespace="myCompany.com")
  • ziggy
    ziggy about 12 years
    I tried that and it looks like i need to specify the namespace on each field as well. Is there any way i can specify the namespace globally?
  • Petru Gardea
    Petru Gardea about 12 years
    I would use the @XmlSchema annotation at the package level. It would look like this: @javax.xml.bind.annotation.XmlSchema(namespace="myCompany.co‌​m", elementFormDefault=javax.xml.bind.annotation.XmlNsForm.QUALI‌​FIED) package com.mypackage;