Hi Keith et
al.
I've just spent some
time playing with mapping with the Unmarshaller, and I have a couple of
observations/questions.
With
0.9.5 and org.exolab.castor.builder.javaclassmapping=type and a split schema in
two namespaces:
split-namespace-1.xsd::
<?xml version="1.0"
encoding="UTF-8"?>
<schema targetNamespace="http://www.xyz.com/test"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:test="http://www.xyz.com/test"
xmlns:test2="http://www.xyz.com/test2"
elementFormDefault="qualified">
<import namespace="http://www.xyz.com/test2"
schemaLocation="split-namespace-2.xsd"/>
<complexType
name="e">
<sequence>
<element name="stringField" type="string"/>
<element name="intField" type="int"/>
<element name="f" type="test2:f"/>
</sequence>
</complexType>
</schema>
split-namespace-2.xsd::
<?xml version="1.0" encoding="UTF-8"?>
<schema targetNamespace="http://www.xyz.com/test2"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:test="http://www.xyz.com/test2"
elementFormDefault="qualified">
<complexType
name="f">
<sequence>
<element name="stringField" type="string"/>
<element name="intField" type="int"/>
</sequence>
</complexType>
</schema>
Suppose I have the
following an XML
message:
<e
xmlns=\"http://www.xyz.com/test\">
<stringField>aString</stringField>
<intField>1</intField>
<f>
<stringField>bString</stringField>
<intField>2</intField>
</f>
</e>
then unmarshalling with the following code works
ok:
Reader reader = new StringReader(input1);E e = (E)Unmarshaller.unmarshal(E.class, reader);
If I use MappingTool to generate a mapping, I get the
following:
<?xml version="1.0" encoding="UTF-8"?>
<mapping xmlns="http://castor.exolab.org/" xmlns:cst="http://castor.exolab.org/">
<description>Castor generated mapping file</description>
<class cst:name="F">
<description>Default mapping for class F</description>
<map-to cst:xml="f" cst:ns-uri="http://www.xyz.com/test2"/>
<field cst:name="stringField" cst:type="java.lang.String" cst:required="true">
<bind-xml name="stringField" node="element"/>
</field>
<field cst:name="intField" cst:type="int" cst:required="true">
<bind-xml name="intField" node="element"/>
</field>
</class>
<class cst:name="E">
<description>Default mapping for class E</description>
<map-to cst:xml="e" cst:ns-uri="http://www.xyz.com/test"/>
<field cst:name="stringField" cst:type="java.lang.String" cst:required="true">
<bind-xml name="stringField" node="element"/>
</field>
<field cst:name="intField" cst:type="int" cst:required="true">
<bind-xml name="intField" node="element"/>
</field>
<field cst:name="f" cst:type="F" cst:required="true">
<bind-xml name="f" node="element"/>
</field>
</class>
</mapping>
<mapping xmlns="http://castor.exolab.org/" xmlns:cst="http://castor.exolab.org/">
<description>Castor generated mapping file</description>
<class cst:name="F">
<description>Default mapping for class F</description>
<map-to cst:xml="f" cst:ns-uri="http://www.xyz.com/test2"/>
<field cst:name="stringField" cst:type="java.lang.String" cst:required="true">
<bind-xml name="stringField" node="element"/>
</field>
<field cst:name="intField" cst:type="int" cst:required="true">
<bind-xml name="intField" node="element"/>
</field>
</class>
<class cst:name="E">
<description>Default mapping for class E</description>
<map-to cst:xml="e" cst:ns-uri="http://www.xyz.com/test"/>
<field cst:name="stringField" cst:type="java.lang.String" cst:required="true">
<bind-xml name="stringField" node="element"/>
</field>
<field cst:name="intField" cst:type="int" cst:required="true">
<bind-xml name="intField" node="element"/>
</field>
<field cst:name="f" cst:type="F" cst:required="true">
<bind-xml name="f" node="element"/>
</field>
</class>
</mapping>
If I try to use this generated mapping with the following
unmarshalling code:
Reader reader = new StringReader(inputString);InputSource source = new InputSource(new StringReader(mappingString));Mapping mapping = new Mapping(getClass().getClassLoader());mapping.loadMapping(source);Unmarshaller unm = new Unmarshaller(mapping);E e = (E)unm.unmarshal(reader);
I get the dreaded "unable to find FieldDescriptor for 'stringField' in
ClassDescriptor of e"
exception.
I believe that the error
may be with MappingTool. Looking at some of the examples, I see mappings
like
<?xml version="1.0"?>
<mapping xmlns:xyz="http://www.acme.org/xyz">
<class name="Root">
<map-to xml="root" ns-prefix="xyz" ns-uri="http://www.acme.org/xyz"/>
<field name="name" type="string">
<bind-xml name="xyz:name" node="attribute"/>
</field>
<field name="child" type="Child">
<bind-xml name="xyz:child" node="element"/>
</field>
</class>
<mapping xmlns:xyz="http://www.acme.org/xyz">
<class name="Root">
<map-to xml="root" ns-prefix="xyz" ns-uri="http://www.acme.org/xyz"/>
<field name="name" type="string">
<bind-xml name="xyz:name" node="attribute"/>
</field>
<field name="child" type="Child">
<bind-xml name="xyz:child" node="element"/>
</field>
</class>
<class
name="Child">
<field name="content" type="string">
<bind-xml node="text"/>
</field>
</class>
<field name="content" type="string">
<bind-xml node="text"/>
</field>
</class>
</mapping>
which include a
ns-prefix for the target namespace. If I change the generated mapping to
include prefixes for the target namespaces, the unmarshalling
works.
<mapping xmlns="http://castor.exolab.org/" xmlns:cst="http://castor.exolab.org/" xmlns:test="http://www.xyz.com/test"
xmlns:test2="http://www.xyz.com/test2">
<class cst:name="F">
<map-to
cst:xml="f" cst:ns-prefix="test2" cst:ns-uri="http://www.xyz.com/test2"/>
<field cst:name="stringField"
cst:type="java.lang.String" cst:required="true">
<bind-xml
name="test2:stringField" node="element"/>
</field>
...
</mapping>
I am surprised that not more use is made of the descriptor
class files when mapping generated classes. In the current example, I had
naively thought that it should be possible to just provide a skelton mapping,
with the missing details being drawn from the descriptor classes.
Specifically, I had thought
<mapping
xmlns="http://castor.exolab.org/" xmlns:cst="http://castor.exolab.org/" xmlns:test="http://www.xyz.com/test">
<class cst:name="E">
<map-to cst:xml="e"
cst:ns-prefix="test" cst:ns-uri="http://www.xyz.com/test"/>
</class>
</mapping>would be enough to
make the current example work, since the field descriptors and child class
descriptors could be sourced from the descriptor classes. However, this
appears not to be the case, and instead, I need to provide a complete mapping of
all classes and fields. I guess that this is the reason that the
MappingTool exists.
I think I am
suggesting that where generated classes are being mapped, that the mapping
operate as an override for the descriptor classes, rather than as a parallel
representation. There are probably valid reasons why this is not the
case.
Regards and thanks
for past help
Dean