Search code examples
javamavenjaxbxml-namespaces

Java : Not getting namespace in generated XML


I have to build an XML file from a java object in a java maven project. I have a class named CrossIndustryInvoice with XML annotations.

@Data
@Builder
@AllArgsConstructor @NoArgsConstructor
@XmlRootElement(name="CrossIndustryInvoice", namespace = NamespaceMapper.RSM_URI)
@XmlAccessorType(XmlAccessType.FIELD)
public
class CrossIndustryInvoice {
    @XmlElement(name = "ExchangedDocumentContext", namespace = NamespaceMapper.RSM_URI)
    private ExchangedDocumentContext exchangedDocumentContext;

    @XmlElement(name = "ExchangedDocument", namespace = NamespaceMapper.RSM_URI)
    private ExchangedDocument exchangedDocument;

    @XmlElement(name = "SupplyChainTradeTransaction", namespace = NamespaceMapper.RSM_URI)
    private SupplyChainTradeTransaction supplyChainTradeTransaction;
}

I also created a class named NamespaceMapper where i define the different namespaces used in my XML

public class NamespaceMapper extends NamespacePrefixMapper {
    public static final String QDT_PREFIX = "qdt"; // DEFAULT NAMESPACE
    public static final String QDT_URI = "urn:un:unece:uncefact:data:standard:QualifiedDataType:100";

    public static final String RAM_PREFIX = "ram"; // DEFAULT NAMESPACE
    public static final String RAM_URI = "urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100";

    public static final String RSM_PREFIX = "rsm"; // DEFAULT NAMESPACE
    public static final String RSM_URI = "urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100";

    public static final String UDT_PREFIX = "udt"; // DEFAULT NAMESPACE
    public static final String UDT_URI = "urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100";

    public static final String XSI_PREFIX = "xsi"; // DEFAULT NAMESPACE
    public static final String XSI_URI = "http://www.w3.org/2001/XMLSchema-instance";

    @Override
    public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
        if(QDT_PREFIX.equals(namespaceUri)) {
            return QDT_PREFIX;
        }
        if(RAM_PREFIX.equals(namespaceUri)) {
            return RAM_PREFIX;
        }
        if(RSM_PREFIX.equals(namespaceUri)) {
            return RSM_PREFIX;
        }
        if(UDT_PREFIX.equals(namespaceUri)) {
            return UDT_PREFIX;
        }
        if(XSI_PREFIX.equals(namespaceUri)) {
            return XSI_PREFIX;
        }
        return suggestion;
    }

    @Override
    public String[] getPreDeclaredNamespaceUris() {
        return new String[] { QDT_URI, RAM_URI, RSM_URI, UDT_URI, XSI_URI };
    }
}

I also created a package-info.java file

@XmlSchema(
        elementFormDefault= XmlNsForm.QUALIFIED,
        namespace="http://www.example.com/FOO",
        xmlns={
                @XmlNs(
                        prefix="ns1",
                        namespaceURI="http://www.example.com/FOO"),
                @XmlNs(
                        prefix="qdt",
                        namespaceURI="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"),
                @XmlNs(
                        prefix="ram",
                        namespaceURI="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"),
                @XmlNs(
                        prefix="rsm",
                        namespaceURI="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"),
                @XmlNs(
                        prefix="udt",
                        namespaceURI="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"),
                @XmlNs(
                        prefix="xsi",
                        namespaceURI="http://www.w3.org/2001/XMLSchema-instance"),
        }
)

package fr.dsidiff.app.ui.model.request.metadata;

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

In my application, I do have a method that converts Java Object to XML String.

private String payloadToXml(CrossIndustryInvoice invoice) throws JAXBException {
    //Create JAXB Context
    JAXBContext ctx = null;
    try {
        ctx = JAXBContext.newInstance(CrossIndustryInvoice.class);
        Marshaller jaxbMarshaller = ctx.createMarshaller();
        jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        StringWriter sw = new StringWriter();
        jaxbMarshaller.marshal(invoice, sw);
        return sw.toString();
    } catch (JAXBException e) {
        e.printStackTrace();
        throw new JAXBException("Oops something went wrong");
    }
}

My problem is that the XML i generate is invalid and namespaces are not matching.

here is a sample of XML I obtain :

<ns2:CrossIndustryInvoice xmlns="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:ns2="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:ns4="urn:un:unece:uncefact:data:standard:QualifiedDataType:100" xmlns:ns3="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
    <ns2:ExchangedDocumentContext>
        <BusinessProcessSpecifiedDocumentContextParameter>
            <ID>A1</ID>
        </BusinessProcessSpecifiedDocumentContextParameter>
        <GuidelineSpecifiedDocumentContextParameter>
            <ID>urn:factur-x.eu:1p0:basicwl</ID>
        </GuidelineSpecifiedDocumentContextParameter>
    </ns2:ExchangedDocumentContext>

While i should get something different:

<?xml version='1.0' encoding='UTF-8'?>
<rsm:CrossIndustryInvoice xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <rsm:ExchangedDocumentContext>
      <ram:BusinessProcessSpecifiedDocumentContextParameter>
         <ram:ID>A1</ram:ID>
      </ram:BusinessProcessSpecifiedDocumentContextParameter>
      <ram:GuidelineSpecifiedDocumentContextParameter>
         <ram:ID>urn:factur-x.eu:1p0:basicwl</ram:ID>
      </ram:GuidelineSpecifiedDocumentContextParameter>
   </rsm:ExchangedDocumentContext>

Solution

  • I didn't pay attention to the import. In my pom.xml I added the following dependency:

    <!-- https://mvnrepository.com/artifact/com.sun.xml.bind/jaxb-impl -->
    <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.0.1</version>
    </dependency>
    

    In my NamespaceMapper class I was using the following import import com.sun.xml.bind.marshaller.NamespacePrefixMapper;

    I replaced it with : import com.sun.xml.internal.bind.marshaller.NamespacePrefixMapper;