xmlgradlexsdjaxbxjc

How to make JAXB use custom namespace prefixes


When marshalling an object to XML with JAXB, it automatically generates namespace prefixes like ns2:. The system I have to communicate with unfortunately doesn't work with these default prefixes (despite the fact that the XML is perfectly valid), so I want to create a mapping of the prefixes there should be for all different namespaces. The XSD is also used for other projects, so I would prefer not to have to make any changes in it.

I found 2 solutions in other answers and on other websites:

  1. Use a namespace prefix mapper class. Sounds perfect, but unfortunately this is no longer an option, as the relevant property no longer exists on the marshaller (using jakarta.xml.bind:jakarta.xml.bind-api:4.0.0).

  2. Add XmlNs annotations in package-info.java. This seems like the only option that's left (besides search/replace in the XML file after marshalling), but this file is generated: all Java classes are generated from the XSD with an XJC task using Gradle. Manual additions of such annotations to the package-info files would be overwritten by the next run of a generate task.

My questions: is there a way to provide JAXB with my own prefix mapping? Or is there a way to have XJC generate those XmlNs annotations automatically?


Solution

  • HiSrc HyperJAXB Annox provides an XJC plugin that can add Java annotations to your generated package-info.java. You can add an annotation to specify a custom xmlns. To use it, add the jar (below) to your XJC classpath and add this argument to your XJC invocation, -Xannotate.

    XJC Add-On Jar

    <groupId>org.patrodyne.jvnet</groupId>
    <artifactId>hisrc-hyperjaxb-annox-plugin</artifactId>
    <version>2.1.0</version>
    

    Configure the annox extension in your bindings file at any one complexType, like this ...

    Bindings Example

    <?xml version="1.0" encoding="UTF-8"?>
    <jaxb:bindings jaxb:version="3.0"
        xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
        xmlns:xsd="http://www.w3.org/2001/XMLSchema"
        xmlns:annox="http://jvnet.org/basicjaxb/xjc/annox"
        jaxb:extensionBindingPrefixes="annox"
    >
        <jaxb:bindings schemaLocation="PurchaseOrder.xsd" node="/xsd:schema" >
            <jaxb:bindings node="xsd:element[@name='purchaseOrder']/xsd:complexType">
                ...
                <annox:annotatePackage>
                    @jakarta.xml.bind.annotation.XmlSchema(
                        xmlns = {
                            @jakarta.xml.bind.annotation.XmlNs(prefix = "po", namespaceURI = "http://example.org/po")
                        })
                </annox:annotatePackage>
                ...
        </jaxb:bindings>
    </jaxb:bindings>
    

    Each time you run your XJC action in your build, the package-info.java class should include your defined XmlNs prefix.

    Disclaimer: I am the maintainer of the forked HiSrc projects.

    BTW, in the Eclipse JAXB implementation, the NamespacePrefixMapper and its property can be found at:

    Mapper: org.glassfish.jaxb.runtime.marshaller.NamespacePrefixMapper
    Used By: org.glassfish.jaxb.runtime.v2.runtime.MarshallerImpl
    Property: org.glassfish.jaxb.namespacePrefixMapper