Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't unmarshal marshalled document when default namespace used

I set up a repo which shows my problem: https://github.com/Waxolunist/stackoverflow.34392476

I try to unmarshal a simple xml document:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
     <Export xmlns="urn:adcubum:Syrius">
         <ExportInhalt/>
         <ExportKopf>
             <Quelle>lokal</Quelle>
         </ExportKopf>
         <SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
     </Export>
</for:document>

This is the document I get from following code:

    Document document = new Document();
    Export export = new Export();
    ExportKopf exportKopf = new ExportKopf();
    exportKopf.setQuelle("lokal");
    export.setExportKopf(exportKopf);
    ExportInhalt exportInhalt = new ExportInhalt();
    export.setExportInhalt(exportInhalt);
    export.setSchemaVersion("bec811a9807a8c8da403d70b9b5e22ad");
    document.setExport(export);

    JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
    Marshaller marshaller = jaxbContext.createMarshaller();
    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
    marshaller.marshal(document, System.out);

Document looks as follows:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "document", namespace = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx")
public class Document {

    @XmlElement(name = "Export", namespace = "urn:adcubum:Syrius")
    private vo.dom.common_service.modul_bl.syrius.Export export;

}

package-info.java

@XmlSchema(
namespace = "urn:adcubum:Syrius",
xmlns = {
    @XmlNs(prefix = "for", namespaceURI = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx"),
    @XmlNs(prefix = "", namespaceURI = "urn:adcubum:Syrius")
}, 
elementFormDefault = XmlNsForm.UNQUALIFIED)

When I try to unmarshal it, I don't get the data mapped:

    JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
    Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();

    InputStream is = this.getClass().getResourceAsStream("/requests/document_simple3.xml");
    XMLInputFactory factory = XMLInputFactory.newInstance();
    XMLStreamReader xmlsr = factory.createXMLStreamReader(is);

    Document document = unmarshaller.unmarshal(xmlsr, Document.class).getValue();

ExportKopf and ExportInhalt are returning null.

Instead following xml works. The only difference is the namespace prefix:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
    <ns3:Export xmlns:ns3="urn:adcubum:Syrius">
        <ExportInhalt/>
        <ExportKopf>
            <Quelle>lokal</Quelle>
        </ExportKopf>
        <SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
    </ns3:Export>
</for:document>

I am using eclipselink moxy.

What do I have to change, so that unmarshaling the marshaled document works.

like image 628
Christian Avatar asked Dec 21 '15 09:12

Christian


2 Answers

I think it's always a good idea to see the actual XSD schema of your mapping whenever something strange like this is happening in JAXB. You could easily do that with the following code.

JAXBContext jaxbContext = JAXBContext.newInstance(Document.class);
jaxbContext.generateSchema(new SchemaOutputResolver() {

    @Override
    public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
        StreamResult streamResult = new StreamResult(new PrintWriter(System.err) {
            @Override
            public void close() {
            }
        });
        streamResult.setSystemId(suggestedFileName);
        return streamResult;
    }
});

That will print the schema(s) that should reflect your JAXB model (you can use another writer to write them to a file). The XSD files are usually very revealing about these kind of issues. I think the problem in your case is the @XmlSchema mapping. You should try to use elementFormDefault = XmlNsForm.QUALIFIED instead. It's always a good idea to use QUALIFIED whenever you're working with multiple namespaces in your mapping.

EDIT: while the main problem with your JAXB mapping was the wrong and/or missing value for the elementFormDefault there were other things that had to be fixed for the code in your repo to work.

  • the Export element in the Document was missing a namespace declaration (from your example, the Document and Export elements are parts of different namespaces)
  • missing elementFormDefault = XmlNsForm.QUALIFIED from the export package
  • wrong namespace value for your main package @XmlSchema annotation (was urn:stackoverflow:exportnamespace instead of urn:stackoverflow:documentnamespace in which the Document element should be)
  • wrong import for jdk_jaxb/UnmarshallerTest.java - it was importing the model.eclipselink.Document instead of model.sun.Document
like image 123
Nándor Előd Fekete Avatar answered Sep 27 '22 20:09

Nándor Előd Fekete


EDIT: Here's the updated code https://github.com/MojoJojo/stackoverflow.34392476

Okay, here's the working version with all moxy_jaxb test passing. Because you said you are using moxy, I left out the changes for model.sun.* packages. If you understand the concept below, you should be able to fix it easily on your own.

First, I cleaned up namespace declarations in your mode.* packages. Most of the times, the declarations and bindings inside package-info.java suffice. Declaring them over and over again on package, entities, fields will add to complexity and unwanted behavior. Check out this link for details. There is no need to re-declare them on the individual Models/Entities themselves, unless there is a strong reason to do otherwise. Next, the test xml itself was a little broken. Fixed the test xml with proper prefixes wherever necessary:

First, model.eclipselink.Document.java

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "document")
public class Document {
    @XmlElement(name = "Export", namespace="urn:adcubum:Syrius")
    private Export export;
    public Export getExport() {
        return export;
    }
    public void setExport(Export export) {
        this.export = export;
    }
}

model.eclipselink.package-info.java:

@XmlSchema(namespace = "http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx",
elementFormDefault = XmlNsForm.QUALIFIED)
package model.eclipselink;

import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;

Similar refactoring on model.eclipselink.export.packageinfo.java:

@XmlSchema(namespace = "urn:adcubum:Syrius",
elementFormDefault = XmlNsForm.QUALIFIED)
package model.eclipselink.export;
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.Xml

And on Export.java:

package model.eclipselink.export;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;

import org.eclipse.persistence.oxm.annotations.XmlElementNillable;

@XmlAccessorType(XmlAccessType.FIELD)
@XmlRootElement(name = "Export")

@XmlType(name = "Export", propOrder = {
        "exportInhalt",
        "exportKopf",
        "schemaVersion"
    })
public class Export {

    @XmlElement(name = "ExportKopf", required = true)
    private ExportKopf exportKopf;

    @XmlElement(name = "ExportInhalt", required = true)
    private ExportInhalt exportInhalt;

    @XmlElement(name = "SchemaVersion", required = true)
    private String schemaVersion;

    public ExportKopf getExportKopf() {
        return exportKopf;
    }

    public void setExportKopf(ExportKopf exportKopf) {
        this.exportKopf = exportKopf;
    }

    public ExportInhalt getExportInhalt() {
        return exportInhalt;
    }

    public void setExportInhalt(ExportInhalt exportInhalt) {
        this.exportInhalt = exportInhalt;
    }

    public String getSchemaVersion() {
        return schemaVersion;
    }

    public void setSchemaVersion(String schemaVersion) {
        this.schemaVersion = schemaVersion;
    }

}

And the few tweaks to your xml files for prefixes.Here's document_prefix.xml

<?xml version="1.0" encoding="UTF-8"?>
<for:document xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
    <ns1:Export xmlns:ns1="urn:adcubum:Syrius">
        <ns1:ExportKopf>
            <ns1:Quelle>lokal</ns1:Quelle>
        </ns1:ExportKopf>
        <ns1:ExportInhalt/>
        <ns1:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns1:SchemaVersion>
    </ns1:Export>
</for:document>

document.xml:

<?xml version="1.0" encoding="UTF-8"?>
<for:document
    xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx" xmlns="urn:adcubum:Syrius">
    <Export>
        <ExportKopf>
            <Quelle>lokal</Quelle>
        </ExportKopf>
        <ExportInhalt />
        <SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</SchemaVersion>
    </Export>
</for:document>

and document_realnamespace.xml (Not sure what the purpose of this file is):

<?xml version="1.0" encoding="UTF-8"?>
<for:document xmlns:ns1="urn:adcubum:Syrius" xmlns:for="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrenderer/forwktbx">
    <ns1:Export>
        <ns1:ExportKopf>
            <ns1:Quelle>lokal</ns1:Quelle>
        </ns1:ExportKopf>
        <ns1:ExportInhalt/>
        <ns1:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns1:SchemaVersion>
    </ns1:Export>
</for:document>

And you run mvn clean test:

Running moxy_jaxb.MarshallerTest
Context class: class org.eclipse.persistence.jaxb.JAXBContext
<?xml version="1.0" encoding="UTF-8"?>
<document xmlns="http://www.adcubum.com/wsdl/global/callout/syrius/modul_bl/doc/service/documentrend
erer/forwktbx" xmlns:ns0="urn:adcubum:Syrius">
   <ns0:Export>
      <ns0:ExportInhalt/>
      <ns0:ExportKopf>
         <ns0:Quelle>lokal</ns0:Quelle>
      </ns0:ExportKopf>
      <ns0:SchemaVersion>bec811a9807a8c8da403d70b9b5e22ad</ns0:SchemaVersion>
   </ns0:Export>
</document>
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.044 sec
Running moxy_jaxb.UnmarshallerTest
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Context class: class org.eclipse.persistence.jaxb.JAXBContext
lokal
Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.033 sec
like image 39
MojoJojo Avatar answered Sep 27 '22 21:09

MojoJojo