If you are using the default JAXB implementation provided with Java 6 or later, you can configure the namespace prefixes by extending the NamespacePrefixMapper and setting a property to tell the marshaller to use your extension.
For more details on marshalling JAXB objects to XML, review this previous JAXB tutorial on Marshalling and Unmarshalling.
Dependencies
Since you need to extend a class that is defined in the JAXB API’s Reference Implemenation (RI), you must pull it in as a dependency.
You can download the libraries directly from jaxb.java.net, or you can add the Maven dependencies.
<dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-impl</artifactId> <version>2.2.11</version> </dependency> <dependency> <groupId>com.sun.xml.bind</groupId> <artifactId>jaxb-core</artifactId> <version>2.2.11</version> </dependency>
NamespacePrefixMapper
Once you have the JAXB libraries, you can extend the com.sun.xml.bind.marshaller.NamespacePrefixMapper class. This is the core class that provides the mapping of XML namespaces to the desired prefix.
Sample extension (using Java 8 syntax)
package com.intertech; import java.util.HashMap; import java.util.Map; import com.sun.xml.bind.marshaller.NamespacePrefixMapper; /** * Implementation of {@link NamespacePrefixMapper} that maps the schema * namespaces more to readable names. Used by the jaxb marshaller. Requires * setting the property "com.sun.xml.bind.namespacePrefixMapper" to an instance * of this class. * <p> * Requires dependency on JAXB implementation jars * </p> */ public class DefaultNamespacePrefixMapper extends NamespacePrefixMapper { private Map<String, String> namespaceMap = new HashMap<>(); /** * Create mappings. */ public DefaultNamespacePrefixMapper() { namespaceMap.put("http://www.w3.org/2001/XMLSchema-instance", "xsi"); namespaceMap.put("https://www.intertech.com/software-consulting-services/", "consult"); namespaceMap.put("http://www.w3.org/2003/05/soap-envelope/", "soap"); } /* (non-Javadoc) * Returning null when not found based on spec. * @see com.sun.xml.bind.marshaller.NamespacePrefixMapper#getPreferredPrefix(java.lang.String, java.lang.String, boolean) */ @Override public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) { return namespaceMap.getOrDefault(namespaceUri, suggestion); } }
Configure
Set the “com.sun.xml.bind.namespacePrefixMapper” property on the marshaller to an instance of your mapper. Once set, any time you marshal your JAXB object to XML, it will use your mapper to get the prefix for a given namespace.
Spring’s Jaxb2Marshaller
To configure Spring’s Jaxb2Marshaller to use your NamespacePrefixMapper, you should set the marshallerProperties map on the Jaxb2Marshaller bean.
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="marshallerProperties"> <map> <entry key="com.sun.xml.bind.namespacePrefixMapper"> <bean class="com.intertech.DefaultNamespacePrefixMapper"/> </entry> </map> </property> </bean>
Java’s Marshaller
To configure the javax.xml.bind.Marshaller, you can set the property directly on the marshaller by calling marshaller.setProperty(“com.sun.xml.bind.namespacePrefixMapper”, new DefaultNamespacePrefixMapper());
Example: (line 25)
import javax.xml.bind.*; import javax.xml.stream.*; import java.io.*; public class SomeService { // JAXBContext is thread safe and can be created once private JAXBContext jaxbContext; public SomeService() { try { // create context with ":" separated list of packages that // contain your JAXB ObjectFactory classes jaxbContext = JAXBContext.newInstance( "com.intertech.consulting" + ":org.w3._2003._05.soap_envelope"); } catch (Exception e) { throw new IllegalStateException(e); } } public String marshal(JAXBElement<?> jaxbElement) { try { Marshaller marshaller = jaxbContext.createMarshaller(); marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new DefaultNamespacePrefixMapper()); StringWriter stringWriter = new StringWriter(); marshaller.marshal(jaxbElement, stringWriter); return stringWriter.toString(); } catch (Exception e) { throw new IllegalStateException(e); } } }
Note: If you use the same mappings across your application, you can create one instance of the mapper and share it.