Skip to main content

Special handling needed when serializing when attribute is in a namespace?

3 replies [Last post]
mfikes
Offline
Joined: 2005-07-06
Points: 0

I encounter an exception when attempting to serialize XML as Fast Infoset if it contains an attribute in a namespace and the JDOM tree is constructed manually via the JDOM API. On the other hand, if the JDOM tree is produced by deserializing equivalent XML, the FastInfoset library doesn't throw. This occurs with revisions 1.1.7 and 1.0.2 of the FastInfoset library.

My question:

Is this a defect or limitation in the FastInfoset library, or am I failing to do something (such as add some code to work with external vocabularies)?

This may or may not be related to a similar thread "IOException: namespace URI of local name not indexed" that occurred in Jan 2006, but below are details of what I'm seeing.

Four JUnit test cases illustrating failure mode and variants that succeed:

-----8<----------------------------

import java.io.ByteArrayOutputStream;
import java.io.StringReader;

import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.Namespace;
import org.jdom.input.SAXBuilder;
import org.jdom.output.SAXOutputter;
import org.jdom.output.XMLOutputter;

import com.sun.xml.fastinfoset.sax.SAXDocumentSerializer;

import junit.framework.TestCase;

public class TestFastInfoset extends TestCase {

public void testSerializeFastInfosetWithAttributeInNamespace() throws Exception {
Element element = constructElementManually(true);

serializeFastInfoset(element); // Fails with IOException below
}

public void testSerializeXmlWithAttributeInNamespace() throws Exception {
Element element = constructElementManually(true);

new XMLOutputter().output(element, System.out);
// Produces:
}

public void testSerializeFastInfosetWithAttibuteInNoNamespace() throws Exception {
Element element = constructElementManually(false);

serializeFastInfoset(element); // Succeeds
}

public void testSerializeFastInfosetWithAttributeInNamespace2() throws Exception {
String content = "";

Element element = new SAXBuilder().build(new StringReader(content)).getRootElement();

serializeFastInfoset(element); // Succeeds
}

private Element constructElementManually(boolean putAttributeInNamespace) {
Element element = new Element("element-name");
if (putAttributeInNamespace) {
element.setAttribute("attribute-name", "attribute-value", Namespace.getNamespace("foo-prefix", "foo-ns"));
} else {
element.setAttribute("attribute-name", "attribute-value");
}
return element;
}

private void serializeFastInfoset(Element element) throws JDOMException {
SAXDocumentSerializer serializer = new SAXDocumentSerializer();
serializer.setOutputStream(new ByteArrayOutputStream());

SAXOutputter outputter = new SAXOutputter(serializer);
outputter.output(element);
}
}
-----8<----------------------------

The failure trace that I get with 1.1.7 is:

org.jdom.JDOMException: Exception in startElement: startElement: namespace URI of local name not indexed: foo-ns
at org.jdom.output.SAXOutputter.startElement(SAXOutputter.java:1028)
at org.jdom.output.SAXOutputter.element(SAXOutputter.java:894)
at org.jdom.output.SAXOutputter.elementContent(SAXOutputter.java:1093)
at org.jdom.output.SAXOutputter.output(SAXOutputter.java:692)
at com.realops.common.xml.TestFastInfoset.serializeFastInfoset(TestFastInfoset.java:61)
at com.realops.common.xml.TestFastInfoset.testSerializeFastInfosetWithAttributeInNamespace(TestFastInfoset.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.io.IOException: namespace URI of local name not indexed: foo-ns
at com.sun.xml.fastinfoset.sax.SAXDocumentSerializer.startElement(SAXDocumentSerializer.java:162)
at org.jdom.output.SAXOutputter.startElement(SAXOutputter.java:1025)
... 23 more
Caused by: java.io.IOException: namespace URI of local name not indexed: foo-ns
at com.sun.xml.fastinfoset.sax.SAXDocumentSerializer.startElement(SAXDocumentSerializer.java:162)
at org.jdom.output.SAXOutputter.startElement(SAXOutputter.java:1025)
at org.jdom.output.SAXOutputter.element(SAXOutputter.java:894)
at org.jdom.output.SAXOutputter.elementContent(SAXOutputter.java:1093)
at org.jdom.output.SAXOutputter.output(SAXOutputter.java:692)
at com.realops.common.xml.TestFastInfoset.serializeFastInfoset(TestFastInfoset.java:61)
at com.realops.common.xml.TestFastInfoset.testSerializeFastInfosetWithAttributeInNamespace(TestFastInfoset.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Caused by: java.io.IOException: namespace URI of local name not indexed: foo-ns
at com.sun.xml.fastinfoset.Encoder.encodeLiteralAttributeQualifiedNameOnSecondBit(Encoder.java:909)
at com.sun.xml.fastinfoset.sax.SAXDocumentSerializer.encodeAttribute(SAXDocumentSerializer.java:608)
at com.sun.xml.fastinfoset.sax.SAXDocumentSerializer.encodeAttributes(SAXDocumentSerializer.java:568)
at com.sun.xml.fastinfoset.sax.SAXDocumentSerializer.startElement(SAXDocumentSerializer.java:159)
at org.jdom.output.SAXOutputter.startElement(SAXOutputter.java:1025)
at org.jdom.output.SAXOutputter.element(SAXOutputter.java:894)
at org.jdom.output.SAXOutputter.elementContent(SAXOutputter.java:1093)
at org.jdom.output.SAXOutputter.output(SAXOutputter.java:692)
at TestFastInfoset.serializeFastInfoset(TestFastInfoset.java:61)
at TestFastInfoset.testSerializeFastInfosetWithAttributeInNamespace(TestFastInfoset.java:23)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:324)
at junit.framework.TestCase.runTest(TestCase.java:154)
at junit.framework.TestCase.runBare(TestCase.java:127)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.junit3.JUnit3TestReference.run(JUnit3TestReference.java:128)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:460)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:673)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:386)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
mfikes
Offline
Joined: 2005-07-06
Points: 0

I discovered that if I instead have JDOM explicitly add the namespace as a separate call prior to adding the attribute, then the FastInfoset serialization succeeds. Specifically, in the unit tests, if I replace the method that constructs the element with this new one, all tests pass:

private Element constructElementManually(boolean putAttributeInNamespace) {
Element element = new Element("element-name");
if (putAttributeInNamespace) {
Namespace namespace = Namespace.getNamespace("foo-prefix", "foo-ns");
element.addNamespaceDeclaration(namespace);
element.setAttribute("attribute-name", "attribute-value", namespace);
} else {
element.setAttribute("attribute-name", "attribute-value");
}
return element;
}

I've briefly searched the JDOM forums regarding this and came up with nothing. I also pulled down and built the latest JDOM code, and the issue still exists. Nevertheless, given the above, I'm thinking that this is a JDOM bug and not a FastInfoset bug.

Thoughts?

sandoz
Offline
Joined: 2003-06-20
Points: 0

I am not that familiar with JDOM but i think in this case it is the responsibility of the JDOM serializer (whether it be XML or FI) to ensure that the infoset serialized is well-formed i.e. it is not in JDOM or the FI library but in the FI JDOM serialization logic where the error lies.

I recommend looking at the XML JDOM serializer source since it must be writing out namespace declarations that do not explicitly exist in the JDOM tree. You need to do the same for the FI JDOM serializer (which is a bit like you have done already with constructElementManually).

One could argue that this is an issue with the JDOM API since one should never be able to create non-well formed infoset synthetically.

Paul.

sandoz
Offline
Joined: 2003-06-20
Points: 0

Some more info after looking in more detail...

The SAXDocumentSerializer assumes that it is being given well-formed infoset. The SAXOutputter is not giving well-formed infoset to the SAXDocumentSerializer.

One could say this is a bug in SAXOutputter or SAXDocumentSerializer :-)

Paul.