JAXB @XmlAnyElement with default namespace adds prefix when marshalling

1k views Asked by At

I have some JAXB classes that are supposed to map XML that may contain unknown elements which it should preserve.

I created a tiny testcase for this with two classes Thing and Subthing, where Thing also has an @XmlAnyElement List<Element> property.

Source XML, with line wraps and indentation added for readability:

<a:thing xmlns:a="some:uri:a">
  <a:subthing val="1"/>
  <div xmlns="http://www.w3.org/1999/xhtml">
    <p/>
  </div>
  <b:something xmlns:b="some:uri:b"/>
</a:thing>

Result after unmarshal and marshal, again formatted for readability:

<a:thing xmlns:a="some:uri:a">
  <a:subthing val="1"/>
  <div:div xmlns="http://www.w3.org/1999/xhtml"
           xmlns:div="http://www.w3.org/1999/xhtml">
    <p/>
  </div:div>
  <b:something xmlns:b="some:uri:b"/>
</a:thing>

Notice that the div element now has a div namespace prefix and corresponding attribute. It's valid and equivalent to the input, but I don't trust that whatever is supposed to consume this later will handle it correctly (especially since in this case it's html (even though it's xhtml), but it could be something else too).

I checked the unmarshalled object using the debugger, and the DOM element does not have the prefix, so it seems the marshaller adds this prefix.

Is there any way to prevent this?

Complete source:

package-info.java

@XmlSchema(namespace = "some:uri:a", xmlns = {
        @XmlNs(prefix = "a", namespaceURI = "some:uri:a")
})
package p;

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

Thing.java

package p;

import org.w3c.dom.Element;

import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.List;

@XmlRootElement(namespace = "some:uri:a")
public class Thing {
    @XmlElement(namespace = "some:uri:a")
    public Subthing subthing;

    @XmlAnyElement
    public List<Element> other; 
}

Subthing.java

package p;

import javax.xml.bind.annotation.XmlAttribute;

class Subthing {
    @XmlAttribute
    public int val;
}

Test case (groovy syntax):

    @Test
    void opaqueXMLNamespaceHandling2() {
        def xml = '<a:thing xmlns:a="some:uri:a"><a:subthing val="1"/><div xmlns="http://www.w3.org/1999/xhtml"><p/></div><b:something xmlns:b="some:uri:b"/></a:thing>'
        JAXBContext ctx = JAXBContext.newInstance(Thing.class, Subthing.class);
        Unmarshaller unmarshaller = ctx.createUnmarshaller();
        def thing = (Thing) unmarshaller.unmarshal(new StringReader(xml));
        println thing.subthing.val
        Marshaller m = ctx.createMarshaller();
        m.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
        StringWriter sw = new StringWriter();
        m.marshal(thing, sw)
        println sw.toString()
        thing = (Thing) unmarshaller.unmarshal(new StringReader(sw.toString()));
        println thing.subthing.val
    }
0

There are 0 answers