I have the follow XML after marshall a JAXB class:
<?xml version="1.0" encoding="UTF-8"?>
<foo:Object xsi:schemaLocation="http://foo.com/ http://foo.com/foo.xsd"
xmlns:ns0="http://lipsum.com/bar" xmlns:foo="http://foo.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<foo:Some attr1="601"/>
<foo:Others>
<bar:Another xsi:schemaLocation="http://lipsum.com/bar
http://lipsum.com/bar.xsd" xmlns:bar="http://lipsum.com/bar">
<bar:SomeOther attr2="01"/>
</bar:Another>
</foo:Others>
</foo:Object>
The <foo:Others/> element in the jaxb class are declared as:
@XmlAnyElement(lax = true)
@XmlElementRefs({
@XmlElementRef(name="Another", type=Another.class, required=false)
})
protected List<Object> any;
It may contain an unknow number of other elements with their own namespaces.
The problem:
When i marshall the Some.class object, jaxb put the namespace of the Another.class into the root element as ns0, since i get the <bar:Another> marshalled as Element from another method with their namespace included i don't need it again into the root element.
That is a problem since <bar:Another> is not required, so if i marshall the Some.class object with an empty list i'am goin to have always the xmlns:ns0.
I need the @XmlElementRefs and @XmlElementRef annotations because i need to convert from json to XML and Jackson need to know the type that "any" list could have.
How can i tell to JAXB Oracle/Moxy implementation that:
1.- Ignore the namespaces from @XmlElementRef classes during the marshalling.
2.- Remove the not used namespaces aka NS[0-9] prefixes from the root element.
Any help would be apreciated.
Just in case some one needs this i got a way to remove the unwanted namespaces, the trick is provided from XMLStreamWriter
Step 1.- Create an WrapperXMLStreamWriter class that goin to wrap a XMLStreamWriter.
public class WrapperXMLStreamWriter implements XMLStreamWriter {
private final XMLStreamWriter writer;
public WrapperXMLStreamWriter(XMLStreamWriter writer) {
this.writer = writer;
}
/* (non-Javadoc)
* @see javax.xml.stream.XMLStreamWriter#writeStartElement(java.lang.String)
*/
@Override
public void writeStartElement(String localName) throws XMLStreamException {
// for each overloaded method call to writer do the method
writer.writeStartElement(localName);
}
/* (non-Javadoc)
* @see javax.xml.stream.XMLStreamWriter#writeNamespace(java.lang.String, java.lang.String)
*/
@Override
public void writeNamespace(String prefix, String namespaceURI) throws XMLStreamException {
// Here is the trick
if(!prefix.startsWith("ns")){
writer.writeNamespace(prefix, namespaceURI);
}
}
...
}
Step 2.- Crate a marshaller as usual
Map<String,String> prefixes = new HashMap<String, String>();
//
prefixes.put("http://www.w3.org/2001/XMLSchema-instance","xsi");
prefixes.put("http://foo.com/", "foo");
Marshaller marshaller = AppContextTool.getInstance().getContextForFoo().createMarshaller();
//
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new NamespacePrefixMapperImpl(prefixes));
marshaller.setProperty(Marshaller.JAXB_SCHEMA_LOCATION, "http://foo.com/ http://foo.com/foo.xsd");
3.- Marshall the Foo instance with the given XMLStreamWriter of the first step
Foo foo = new Foo();
ByteArrayOutputStream xml= new ByteArrayOutputStream();
try {
XMLStreamWriter writer =
new WrapperXMLStreamWriter((XMLStreamWriter) XMLOutputFactory.newInstance().createXMLStreamWriter(xml, "UTF-8"));
marshaller.marshal(foo, writer);
} catch (XMLStreamException | FactoryConfigurationError e) {
e.printStackTrace();
}
4.- The result:
<?xml version="1.0" encoding="UTF-8"?>
<foo:Object xsi:schemaLocation="http://foo.com/ http://foo.com/foo.xsd"
xmlns:foo="http://foo.com/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<foo:Some attr1="601"/>
<foo:Others>
<bar:Another xsi:schemaLocation="http://lipsum.com/bar
http://lipsum.com/bar.xsd" xmlns:bar="http://lipsum.com/bar">
<bar:SomeOther attr2="01"/>
</bar:Another>
</foo:Others>
</foo:Object>
No more NS namespaces, Hope this helps someone.