Why do I get a null value back...

Why do I get a null value back from my JAVA object when the data was there in my XML stream?

This is a question, that I have seen over and over with different O2X mapping technologies. Sometime using JAXB, sometime using Web Services, and now with SDO. It's also a common issue with .NET Web services.

I do see the data on the wire or in my XML file, but I am getting a null value once I try to retrive it using the JAVA accessor APIs. How is this possible, is this a bug?

The short answer is No. It's a feature!!! When the instance data do not match with the schema definition, it will be silently ignored by the XML processor (a.k.a. de-serialization layer). Let me try to give a simple example to illustrate this.

XML Schema
 1  <?xml version="1.0" encoding="UTF-8" ?>
2 <xsd:schema xmlns="http://www.oracle.com/ias/automation/dte"
3 xmlns:xsd="http://www.w3.org/2001/XMLSchema"
4 targetNamespace="http://www.oracle.com/ias/automation/dte">
5 <xsd:element name="travelGuide">
6 <xsd:complexType>
7 <xsd:sequence>
8 <xsd:element ref="map"/>
9 </xsd:sequence>
10 </xsd:complexType>
11 </xsd:element>
12 <xsd:element name="map">
13 <xsd:complexType>
14 <xsd:sequence>
15 <xsd:element maxOccurs="unbounded" minOccurs="1" ref="route"/>
16 </xsd:sequence>
17 </xsd:complexType>
18 </xsd:element>
19 <xsd:element name="route">
20 <xsd:complexType>
21 <xsd:sequence>
22 <xsd:element name="from" type="xsd:string"/>
23 <xsd:element name="to" type="xsd:string"/>
24 </xsd:sequence>
25 <xsd:attribute name="distance" type="xsd:int"/>
26 </xsd:complexType>
27 </xsd:element>
28 </xsd:schema>

XML instance

 1  <travelGuide xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
2 xmlns="http://www.oracle.com/ias/automation/dte">
3 <map>
4 <route distance="500">
5 <from>bangalore</from>
6 <to>chennai</to>
7 </route>
8 </map>
9 </travelGuide>

Sample Test Code:

1 package test;
3 import junit.framework.TestCase;
5 import oracle.xml.parser.schema.XMLSchema;
6 import oracle.xml.parser.schema.XSDBuilder;
7 import oracle.xml.parser.v2.DOMParser;
8 import oracle.xml.parser.v2.XMLParseException;
9 import oracle.xml.parser.v2.XMLParser;
11 public class SchemaValidationTest extends TestCase {
12 static final String XML_URI = "file:///dev/howto/jaxb-test/travel.xml";
13 static final String XSD_URI = "file:///dev/howto/jaxb-test/travel.xsd";
15 public SchemaValidationTest(String sTestName) {
16 super(sTestName);
17 }
19 public void testValidation() throws Exception {
20 DOMParser dp = new DOMParser();
21 // Turns Schema Validation on
22 dp.setValidationMode(XMLParser.SCHEMA_VALIDATION);
23 // Uses System.out to get any validation error
24 dp.setErrorStream(System.out);
25 // Set Schema Object for Validation
26 dp.setXMLSchema(new XSDBuilder().build(XSD_URI));
27 dp.parse(XML_URI);
28 }
29 }

The output from the test, with validation errors, looks like this:
file:///dev/howto/jaxb-test/travel.xml<Line 5, Column 10>: XML-24534: (Error) Element 'from' not expected.
file:///dev/howto/jaxb-test/travel.xml<Line 6, Column 8>: XML-24534: (Error) Element 'to' not expected.
file:///dev/howto/jaxb-test/travel.xml<Line 7, Column 11>: XML-24521: (Error) Element not completed: 'route'

The explaination: In the instance data, we have a fully qualified name (or QName) for the element that is '{http://www.oracle.com/ias/automation/dte}from' while the expectation, based on the schema definition was to have an unqualified element (or with an empty namespace) and usulally noted as '{}from'. In other words, a simple impedance mismatch.

Here you have two way to solve the issue:
a) change the schema definition to match with the wire format. In our sample, adding the 'elementFormDefault="qualified"' attribute to the schema is all it takes.

b) change the instance data so that it is consistent with the XML Schema. In our sample, you need to put from and to in no-namespace, by adding an empty default namespace on each element, like this:
 4    <route distance="500">
5 <from xmlns="">bangalore</from>
6 <to xmlns="">chennai</to>
7 </route>

Remember... When you have some doubt, you should make sure that you have the right assumption; make sure that the XML schema and the XML instance data are consistent with each other.

Here is a paper worth reading, if you are new to these concepts: XML Schema: Understanding Namespaces.


Popular posts from this blog

Changing the version of JDK used by JDeveloper

Connection reset from a WCF Web Service

Test locally first, then deploy to the cloud.