Project

Profile

Help

Bug #6387

closed

non-qualified elements declare illegal prefix-emptyNamespace mapping

Added by Grzegorz Grzybek about 1 month ago. Updated 23 days ago.

Status:
Resolved
Priority:
Normal
Assignee:
-
Category:
JAXP Java API
Sprint/Milestone:
Start date:
2024-04-11
Due date:
% Done:

0%

Estimated time:
Legacy ID:
Applies to branch:
12, trunk
Fix Committed on Branch:
12, trunk
Fixed in Maintenance Release:
Platforms:
Java

Description

I have a Camel-XQuery application which processes SOAP messages using CXF and Undertow transport.

Roughly the stack trace looks like this:

org.apache.cxf.interceptor.Fault: Could not generate the XML stream caused by: javax.xml.stream.XMLStreamException: Non-default namespace can not map to empty URI (as per Namespace 1.0 # 2) in XML 1.0 documents.
	at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:130) ~[cxf-core-4.0.2.jar:4.0.2]
	at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:67) ~[cxf-core-4.0.2.jar:4.0.2]
	at org.apache.camel.component.cxf.jaxws.HybridSourceDataBinding$1.write(HybridSourceDataBinding.java:73) ~[camel-cxf-soap-4.0.0.jar:4.0.0]
	...
	at org.apache.cxf.transport.http_undertow.CxfUndertowServlet.invoke(CxfUndertowServlet.java:51) ~[cxf-rt-transports-http-undertow-4.0.2.jar:4.0.2]
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.handleRequest(AbstractHTTPServlet.java:303) ~[cxf-rt-transports-http-4.0.2.jar:4.0.2]
	...
	at org.apache.cxf.transport.servlet.AbstractHTTPServlet.service(AbstractHTTPServlet.java:278) ~[cxf-rt-transports-http-4.0.2.jar:4.0.2]
	at io.undertow.servlet.handlers.ServletHandler.handleRequest(ServletHandler.java:74) ~[undertow-servlet-2.3.10.jar:2.3.10]
	...
	at io.undertow.servlet.spec.AsyncContextImpl$TaskDispatchRunnable.run(AsyncContextImpl.java:553) ~[undertow-servlet-2.3.10.jar:2.3.10]
	at org.jboss.threads.ContextHandler$1.runWith(ContextHandler.java:18) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2513) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1512) ~[jboss-threads-3.5.0.Final.jar:3.5.0.Final]
	at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282) ~[xnio-api-3.8.8.Final.jar:3.8.8.Final]
	at java.base/java.lang.Thread.run(Thread.java:842) ~[na:na]
Caused by: javax.xml.stream.XMLStreamException: Non-default namespace can not map to empty URI (as per Namespace 1.0 # 2) in XML 1.0 documents
	at com.ctc.wstx.sw.BaseStreamWriter.throwOutputError(BaseStreamWriter.java:1596) ~[woodstox-core-6.5.1.jar:6.5.1]
	at com.ctc.wstx.sw.SimpleNsStreamWriter.writeNamespace(SimpleNsStreamWriter.java:135) ~[woodstox-core-6.5.1.jar:6.5.1]
	at org.apache.cxf.staxutils.StaxUtils.writeStartElement(StaxUtils.java:835) ~[cxf-core-4.0.2.jar:4.0.2]
	...
	at org.apache.cxf.databinding.source.XMLStreamDataWriter.write(XMLStreamDataWriter.java:126) ~[cxf-core-4.0.2.jar:4.0.2]
	... 41 common frames omitted

This stack trace shows a problem where CXF/StAX tries to process an element without namespace where its parent element is namespaced.

After digging the problem more, I tracked down how the problematic DOM is created and the stack trace is:

"XNIO-3 task-3@16475" prio=5 tid=0x59 nid=NA runnable
  java.lang.Thread.State: RUNNABLE
	  at net.sf.saxon.dom.DOMWriter.startElement(DOMWriter.java:164)
	  at net.sf.saxon.event.TreeReceiver.startElement(TreeReceiver.java:148)
	  at net.sf.saxon.event.ComplexContentOutputter.startContent(ComplexContentOutputter.java:782)
	  at net.sf.saxon.event.ComplexContentOutputter.characters(ComplexContentOutputter.java:272)
	  at net.sf.saxon.event.ComplexContentOutputter.decompose(ComplexContentOutputter.java:846)
	  at net.sf.saxon.event.ComplexContentOutputter.append(ComplexContentOutputter.java:661)
	  at net.sf.saxon.event.Outputter.append(Outputter.java:341)
	  at net.sf.saxon.expr.elab.PullElaborator.lambda$elaborateForPush$0(PullElaborator.java:40)
	  at net.sf.saxon.expr.elab.PullElaborator$$Lambda$1611/0x00007f317c9a8450.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$4(Block.java:898)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1613/0x00007f317c9a88a0.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$2(Block.java:864)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1615/0x00007f317c9a8cf0.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator.lambda$elaborateForPush$1(Block.java:854)
	  at net.sf.saxon.expr.instruct.Block$BlockElaborator$$Lambda$1616/0x00007f317c9a8f18.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator.lambda$elaborateForPush$0(FixedElement.java:653)
	  at net.sf.saxon.expr.instruct.FixedElement$FixedElementElaborator$$Lambda$1612/0x00007f317c9a8678.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.expr.instruct.UserFunction.process(UserFunction.java:712)
	  at net.sf.saxon.expr.UserFunctionCall$UserFunctionCallElaborator.lambda$elaborateForPush$5(UserFunctionCall.java:846)
	  at net.sf.saxon.expr.UserFunctionCall$UserFunctionCallElaborator$$Lambda$1607/0x00007f317c9a1788.processLeavingTail(Unknown Source:-1)
	  at net.sf.saxon.query.XQueryExpression.processQuery(XQueryExpression.java:499)
	  at net.sf.saxon.query.XQueryExpression.run(XQueryExpression.java:473)
	  at org.apache.camel.component.xquery.XQueryBuilder.evaluateAsDOM(XQueryBuilder.java:234)
	  at org.apache.camel.component.xquery.XQueryBuilder.evaluate(XQueryBuilder.java:194)
	  at org.apache.camel.component.xquery.XQueryBuilder.evaluate(XQueryBuilder.java:169)
	  ...
	  at org.apache.camel.support.processor.DelegateSyncProcessor.process(DelegateSyncProcessor.java:65)
	  at org.apache.camel.impl.engine.CamelInternalProcessor.process(CamelInternalProcessor.java:383)
	  ...
	  at org.apache.camel.component.cxf.jaxws.CxfConsumer$CxfConsumerInvoker.invoke(CxfConsumer.java:162)
	  at org.apache.cxf.interceptor.ServiceInvokerInterceptor$1.run(ServiceInvokerInterceptor.java:59)
	  at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
	  ...
	  at org.apache.cxf.transport.http_undertow.UndertowHTTPHandler.handleRequest(UndertowHTTPHandler.java:122)
	  at io.undertow.server.Connectors.executeRootHandler(Connectors.java:393)
	  at io.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:859)
	  ...
	  at org.xnio.XnioWorker$WorkerThreadFactory$1$1.run(XnioWorker.java:1282)
	  at java.lang.Thread.run(Thread.java:842)

The document being processed looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message xmlns:msg="http://data.example.com">
    <header:header-container xmlns:header="http://header.example.com">
        <header:header1>
            <id>12</id>
            <system-id>33</system-id>
            <time />

According to XSD, msg:soap-message, header:header-container and header:header1 are qualified elements, but id, system-id and time are defined like this:

<xsd:complexType name="header1">
    <xsd:sequence>
        <xsd:element name="id" nillable="true" type="xsd:string">
        </xsd:element>
        <xsd:element name="system-id" nillable="true" type="xsd:string">
        </xsd:element>
...

because id and system-id don't have form attribute and there's no explicit elementFormDefault="qualified", these elements effective are in no namespace at all.

When taking this document literally and parsing it using standard JAXP DOM, I can confirm it by printing QNames and namespaces:

<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message> (msg:http://data.example.com)
  <header:header-container> (header:http://header.example.com)
    <header:header1> (header:http://header.example.com)
      <id> (null:null)
      <system-id> (null:null)
      <time> (null:null)
...

When changing this document to:

<?xml version="1.0" encoding="UTF-8"?>
<msg:soap-message> (msg:http://data.example.com)
  <header:header-container> (header:http://header.example.com)
    <header:header1> (header:http://header.example.com)
      <id xmlns:header=""> (null:null)
      <system-id> (null:null)
      <time> (null:null)
...

I'm getting:

[Fatal Error] :5:32: The value of the attribute "prefix="xmlns",localpart="header",rawname="xmlns:header"" is invalid. Prefixed namespace bindings may not be empty.

org.xml.sax.SAXParseException; lineNumber: 5; columnNumber: 32; The value of the attribute "prefix="xmlns",localpart="header",rawname="xmlns:header"" is invalid. Prefixed namespace bindings may not be empty.

	at java.xml/com.sun.org.apache.xerces.internal.parsers.DOMParser.parse(DOMParser.java:261)
	at java.xml/com.sun.org.apache.xerces.internal.jaxp.DocumentBuilderImpl.parse(DocumentBuilderImpl.java:339)
	at java.xml/javax.xml.parsers.DocumentBuilder.parse(DocumentBuilder.java:122)
...

And this is exactly what Saxon-HE 12.4 is doing in net.sf.saxon.dom.DOMWriter#startElement():

  • elemName parameter is "id"
  • attributes parameter is net.sf.saxon.om.EmptyAttributeMap
  • namespaces parameter is:
namespaces = {net.sf.saxon.om.NamespaceMap@12206} ""
 prefixes: java.lang.String[]  = {java.lang.String[0]@16626} []
 uris: net.sf.saxon.om.NamespaceUri[]  = {net.sf.saxon.om.NamespaceUri[0]@16627} 

nsStack.peek() passed to namespaces.getDifferences() is:

parentNamespaces = {net.sf.saxon.om.NamespaceMap@16534} "header=http://header.example.com "
 prefixes: java.lang.String[]  = {java.lang.String[1]@16633} ["header"]
 uris: net.sf.saxon.om.NamespaceUri[]  = {net.sf.saxon.om.NamespaceUri[1]@16634} 
  0 = {net.sf.saxon.om.NamespaceUri@16638} "http://header.example.com"

While parentNamespaces is fine (matches NS declarations of parent "header:header1" element, the result of namespaces.getDifferences() is:

declarations = {net.sf.saxon.om.NamespaceBinding[1]@16546} 
 0 = {net.sf.saxon.om.NamespaceBinding@16642} "header="
  prefix: java.lang.String  = {@16635} "header"
  uri: net.sf.saxon.om.NamespaceUri  = {net.sf.saxon.om.NamespaceUri@16644} ""

It means that in element "id", org.w3c.dom.Element#setAttributeNS() is called with:

  • namespace: http://www.w3.org/2000/xmlns/
  • qname: xmlns:header
  • nsURI (value): "" (empty string)

In my opinion, net.sf.saxon.om.NamespaceMap#getDifferences() should not simply do:

} else if (j < other.prefixes.length) {
    // prefix present in other map, absent from this: add an undeclaration
    result.add(new NamespaceBinding(other.prefixes[j], NamespaceUri.NULL));

it CAN'T add NULL namespace URI when prefix is not empty.

Sorry for not providing full reproducer, but I hope my analysis is enough.

kind regards Grzegorz Grzybek

Please register to edit this issue

Also available in: Atom PDF