Jaxb ignores namespace when unmarshalling

I am using Jaxb2 and Spring. I am trying to unmount some XML that are sent by two of my clients.

So far, I only had to deal with one client that sent some xml:

<foo xmlns="com.acme"> <bar>[...]</bar> <foo> 

which is associated with POJO as follows:

 @XmlType(name = "", propOrder = {"bar"}) @XmlRootElement(name = "Foo") public class Foo { @XmlElement(name = "Bar") private String bar; [...] } 

I found that the previous developer hardcoded the namespace in unmarshaller to make it work.

Now the second client sends the same XML, but changes the namespace!

 <foo xmlns="com.xyz"> <bar>[...]</bar> <foo> 

Obviously, unmarshaller cannot undo the token because it expects {com.acme}foo instead of {com.xyz}foo . Unfortunately, asking the client to change the XML is not an option.

What I tried:

1) In application-context.xml I was looking for a configuration that would allow me to ignore the namespace, but could not find it:

 <bean id="marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"> <property name="packagesToScan"> <list> <value>com.mycompany.mypkg</value> </list> </property> <property name="marshallerProperties"> <map> <entry key="???"><value type="java.lang.Boolean">false</value></entry> </map> </property> </bean> 

it seems that the only options available are those listed in the Jaxb2Marshaller Javadoc:

 /** * Set the JAXB {@code Marshaller} properties. These properties will be set on the * underlying JAXB {@code Marshaller}, and allow for features such as indentation. * @param properties the properties * @see javax.xml.bind.Marshaller#setProperty(String, Object) * @see javax.xml.bind.Marshaller#JAXB_ENCODING * @see javax.xml.bind.Marshaller#JAXB_FORMATTED_OUTPUT * @see javax.xml.bind.Marshaller#JAXB_NO_NAMESPACE_SCHEMA_LOCATION * @see javax.xml.bind.Marshaller#JAXB_SCHEMA_LOCATION */ public void setMarshallerProperties(Map<String, ?> properties) { this.marshallerProperties = properties; } 

2) I also tried setting up unmarshaller in code:

 try { jc = JAXBContext.newInstance("com.mycompany.mypkg"); Unmarshaller u = jc.createUnmarshaller(); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(false);//Tried this option. DocumentBuilder db = dbf.newDocumentBuilder(); Document doc = db.parse(xmlFile.toFile()); u.unmarshal(new DOMSource(doc)); return (Foo)u.unmarshal(new StreamSource(xmlFile.toFile())); } catch (ParserConfigurationException | SAXException | IOException | JAXBException e) { LOGGER.error("Erreur Unmarshalling CPL"); } 

3) Different form with SAXParser:

 try { jc = JAXBContext.newInstance("com.mycompany.mypkg"); Unmarshaller um = jc.createUnmarshaller(); final SAXParserFactory sax = SAXParserFactory.newInstance(); sax.setNamespaceAware(false); final XMLReader reader = sax.newSAXParser().getXMLReader(); final Source er = new SAXSource(reader, new InputSource(new FileReader(xmlFile.toFile()))); return (Foo)um.unmarshal(er); }catch(...) {[...]} 

It works! . However, I would prefer the Unmarshaller auto-amplifier to be able to use this ugly conf every time without having to.

+9
source share
2 answers

Knowledge of Namesapce is a function of reading / creating / analyzing documents, not marshalers. XML elements from different namespaces represent different == objects, so marshalers cannot ignore them.

You correctly disabled namespaces in your SAX reader and, as you said, it worked. I do not understand your problem with this, your marshaller can still be entered, the difference is in receiving the input.

The same trick with the document creator should also work (I will test it later), I suspect that you still used a marshaller with a โ€œhard-codedโ€ namespace, but your document was free from the namespace.

In my project, I use XSLT to solve a similar problem. Setting up an awpaceness namespace is definitely an easier solution. But with XSLT, I could selectively remove only some namespaces, and also my XML input code is not always identical (ignoring namespaces), and sometimes I have to rename several elements, so XSLT gives me this extra flexibility.

To remove namespaces, you can use the following xslt template:

 <xsl:stylesheet version="1.0" xmlns:e="http://timet.dom.robust.ed" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <xsl:template match="/"> <xsl:copy> <xsl:apply-templates /> </xsl:copy> </xsl:template> <xsl:template match="*"> <xsl:element name="{local-name()}"> <xsl:apply-templates select="@* | node()" /> </xsl:element> </xsl:template> <xsl:template match="@*"> <xsl:attribute name="{local-name()}"> <xsl:value-of select="."/> </xsl:attribute> </xsl:template> <xsl:template match="text() | processing-instruction() | comment()"> <xsl:copy /> </xsl:template> </xsl:stylesheet> 

Then in Java, before de-marshalling, I convert the input:

 Transformer transformer = TransformerFactory.newInstance().newTransformer(stylesource); Source source = new DOMSource(xml); DOMResult result = new DOMResult(); transformer.transform(source, result); 
+2
source

Thanks to everyone, here I shared my solution that works for my code, I try to make it universal so that each namespace contains ":" I write code, if any tag has ":" it will be removed from xml, this is used to skip namespace during unmarshalling using jaxb.

 public class NamespaceFilter { private NamespaceFilter() { } private static final String COLON = ":"; public static XMLReader nameSpaceFilter() throws SAXException { XMLReader xr = new XMLFilterImpl(XMLReaderFactory.createXMLReader()) { private boolean skipNamespace; @Override public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { if (qName.indexOf(COLON) > -1) { skipNamespace = true; } else { skipNamespace = false; super.startElement("", localName, qName, atts); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.indexOf(COLON) > -1) { skipNamespace = true; } else { skipNamespace = false; super.endElement("", localName, qName); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (!skipNamespace) { super.characters(ch, start, length); } } }; return xr; } 

}

for unpacking

 XMLReader xr = NamespaceFilter.nameSpaceFilter(); Source src = new SAXSource(xr, new InputSource("C:\\Users\\binal\\Desktop\\response.xml")); StringWriter sw = new StringWriter(); Result res = new StreamResult(sw); TransformerFactory.newInstance().newTransformer().transform(src, res); JAXBContext jc = JAXBContext.newInstance(Tab.class); Unmarshaller u = jc.createUnmarshaller(); String done = sw.getBuffer().toString(); StringReader reader = new StringReader(done); Tab tab = (Tab) u.unmarshal(reader); System.out.println(tab); 

"

0
source

Source: https://habr.com/ru/post/985103/


All Articles