Read comments inline.
On Fri, 2006-01-06 at 23:44 -0600, Keith Visco wrote:
> Sandeep,
>
> See inline comments...
>
> Sandeep Khanna wrote:
> > Keith,
> >
> > Thanks for your valuable info.
> >
> > A few questions:
> >
> > On Thu, 2006-01-05 at 22:29 -0600, Keith Visco wrote:
> >
> >>You can create a custom field handler to be your GUID generator.
> >>
> >>And then use the following mapping:
> >>
> >><class name="...ClientDcl" identity="clientGUID">
> >> <map-to xml="ClientDcl"/>
> >> ...
> >> <field name="clientGUID" handler="MyGUIDHandler"/>
> >> <bind-xml name="ClientGUID"/>
> >> </field>
> >> ...
> >></class>
> >
> >
> > I want the 'MyGUIDHandler' to be invoked only while Unmarshalling
> > objects and not while Marshalling them.
> >
> > While marshalling, the objects being marshalled already have the GUIDs
> > correctly set on them and is just a matter of printing them out.
> >
>
> Ah ok, well that's easy enough to tweak your handler so that it doesn't
> generate a GUID during marshalling...just have your handler can check
> the respective field in the target object to see if the GUID has been
> set, if so, just return it, if not it can generate one. So during
> marshalling, since the GUID has already been set in the target object,
> it will just return that value.
>
> > While unmarshalling the XML element placeholders are a hint to the
> > Unmarshaller to create & populate the GUIDs on the objects being created
> > from XML.
> >
> > Is this possible?
>
> See my comments above. However, I guess I'm a bit confused on what you
> call a "placeholder". Castor will need an ID to be present in the XML
> during unmarshalling or it won't know which object to reference.
Objects created in the application would already have the GUIDs
generated & correctly set on the parent/child objects. These objects
will be marshalled into something like:
<?xml version="1.0" encoding="UTF-8"?>
<AsClient>
<ClientGUID>34AECA5B-C757-9352-0DE2-5A2144ADC7BC</ClientGUID>
<Sex>M</Sex>
<DateOfBirth>1970-01-01T00:00:00.000-05:00</DateOfBirth>
<TypeCode>02</TypeCode>
<TaxID>999-99-9999</TaxID>
<FirstName>Sandeep</FirstName>
<MiddleInitial>T</MiddleInitial>
<LastName>Khanna</LastName>
<Fields>
<AsClientField>
<key>PhoneType4</key>
<value>
<ClientGUID>34AECA5B-C757-9352-0DE2-5A2144ADC7BC</ClientGUID>
<FieldName>PhoneType4</FieldName>
<TextValue>00</TextValue>
<FieldTypeCode>02</FieldTypeCode>
</value>
</AsClientField>
</Fields>
</AsClient>
This XML will be sent out over the internet via web service calls to a
remote system.
GUID generation is specific to the original system.
A remote system may decide to share Client data via XML but does not
generate the GUIDs. We insert placeholders in the incoming XML to
indicate to the Unmarshaller to create new GUIDs and populate them on
the objects being unmarshalled. The incoming XML may look like:
<?xml version="1.0" encoding="UTF-8"?>
<AsClient>
<ClientGUID/>
<Sex>M</Sex>
<DateOfBirth>1970-01-01T00:00:00.000-05:00</DateOfBirth>
<TypeCode>02</TypeCode>
<TaxID>999-99-9999</TaxID>
<FirstName>Sandeep</FirstName>
<MiddleInitial>T</MiddleInitial>
<LastName>Khanna</LastName>
<Fields>
<AsClientField>
<key>PhoneType4</key>
<value>
<ClientGUID/>
<FieldName>PhoneType4</FieldName>
<TextValue>00</TextValue>
<FieldTypeCode>02</FieldTypeCode>
</value>
</AsClientField>
</Fields>
</AsClient>
To summarize, the marshalled XML is *not* the input for the
Unmarshaller.
>
> >
> >
> >>Once you have your GUID generator working you can then add the following
> >>to your mapping file:
> >>
> >><class name="...AddressRoleDcl">
> >> <map-to xml="AddressRoleDcl"/>
> >> ...
> >> <field name="clientGUID" reference="true">
> >> <bind-xml name="ClientGUID" node="element"/>
> >> </field>
> >> ...
> >></class>
> >
> >
> > After looking at the Castor docs, it appears that the attribute
> > 'reference' is available on element 'bind-xml' rather than on 'field'.
> > Is that correct?
> >
>
> That sounds right...sorry for the confusion...you can place the
> reference="true" on the bind-xml element.
>
> > By just saying reference="true" as shown above, how does the
> > Unmarshaller know that it has to reference the parent/contained object's
> > 'clientGuid' property. Don't we have to say reference so & so property
> > name from the parent object? Or do the property names have to be same on
> > the parent & the contained/child object?
>
> Ah yes, I knew I left out an important note. The GUID must be
> document-unique. Basically references are treated as ID/IDREF within the
> XML, which means each ID must be unique within the document, regardless
> of the element name.
>
> During unmarshalling when Castor finds a field marked as a reference it
> will find the object with the given ID and set the associated field with
> that object.
>
> >
> >
> >>
> >>Keep in mind that your handler (your GUID generator) will need to keep
> >>track of GUIDs during the marshalling for each object that it generates
> >>a GUID for so that when the handler is called again for the same object
> >>it will return the correct GUID for that object as your handler will get
> >>called each time it needs to output the GUID. This will be once for the
> >>object itself and then once for each reference to the object.
> >
> >
> > As per my comments above, I just need the GUID generation & setting
> > functionality while Unmarshalling. Do you still see an issue here?
> >
>
> Yes, I do seen an issue here, because for your fields that reference
> another object Castor will need to know it's ID in order to resolve the
> field properly during unmarshalling.
>
> So I guess I'm now having trouble understanding how you expect things to
> work. During marshalling, you say the object already has a GUID...so
> Castor will just print it out...which is fine...but how does that go
> from having an actual GUID that got printed out into the XML to just
> being a place holder which needs to generate a GUID upon unmarshalling
> back to an object? Shouldn't the GUID still exist in the XML from the
> marshalling?
>From above the marshalled XML is *not* the input for the Unmarshaller.
>
> I guess I need more explaination in order to help you come up with a
> solution.
My current mapping file is:
<?xml version="1.0" encoding="UTF-8"?>
<mapping>
<!--
=================================================================== -->
<!-- Mapping for class com.adminserver.dcl.ClientDcl -->
<!--
=================================================================== -->
<class name="com.adminserver.dcl.ClientDcl" identity="clientGuid"
access="shared"
auto-complete="false">
<map-to table="AsClient" xml="AsClient"/>
<field name="clientGuid" type="string"
get-method="getClientGuid"
set-method="setClientGuid"
handler="com.adminserver.utl.MyGuidHandler">
<bind-xml name="ClientGUID" node="element"/>
</field>
<field name="firstName" type="string" get-method="getFirstName"
set-method="setFirstName">
<bind-xml name="FirstName" node="element"/>
</field>
<field name="lastName" type="string" get-method="getLastName"
set-method="setLastName">
<bind-xml name="LastName" node="element"/>
</field>
<field name="fields" type="com.adminserver.dcl.ClientFieldDcl"
get-method="getFields"
set-method="setFields" collection="map">
<bind-xml name="AsClientField" node="element"
location="Fields">
<class name="org.exolab.castor.mapping.MapItem">
<field name="key" type="java.lang.String" >
<bind-xml name="key"/>
</field>
<field name="value"
type="com.adminserver.dcl.ClientFieldDcl">
<bind-xml name="value"/>
</field>
</class>
</bind-xml>
</field>
</class>
<!--
=================================================================== -->
<!-- Mapping for class com.adminserver.dcl.ClientFieldDcl -->
<!--
=================================================================== -->
<class name="com.adminserver.dcl.ClientFieldDcl"
identity="clientGuid fieldName"
access="shared" auto-complete="false">
<map-to table="AsClientField" xml="AsClientField"/>
<field name="clientGuid" type="string"
get-method="getClientGuid"
set-method="setClientGuid">
<bind-xml name="ClientGUID" node="element"
type="com.adminserver.dcl.ClientDcl"
reference="true"/>
</field>
<field name="fieldName" type="string" get-method="getFieldName"
set-method="setFieldName">
<bind-xml name="FieldName" node="element"/>
</field>
<field name="textValue" type="string" get-method="getTextValue"
set-method="setTextValue">
<bind-xml name="TextValue" node="element"/>
</field>
</class>
</mapping>
With the above mapping in place, I get the following Exception:
[DEBUG]: (TestXMLBindingFrameworks.testCastor:75) - Unmarshalling AsXML
to ClientDcl...
[DEBUG]: (MyGuidHandler.convertUponSet:38) - original setValue value =
[DEBUG]: (MyGuidHandler.convertUponSet:40) - new setValue value =
1402C8BA-6C29-FD7F-ED7D-ABADBB3BED06
[DEBUG]: (TestXMLBindingFrameworks.testCastor:79) - Unmarshalling
successful in 329 milliseconds.
[DEBUG]: (TestXMLBindingFrameworks.testCastor:84) - Marshalling
ClientDcl to AsXML ...
Unable to resolve ID for instance of class 'java.lang.String' due to the
following error: Unable to resolve ClassDescriptor.
at org.exolab.castor.xml.Marshaller.getObjectID(Marshaller.java:2009)
at org.exolab.castor.xml.Marshaller.marshal(Marshaller.java:1649)
at org.exolab.castor.xml.Marshaller.marshal(Marshaller.java:1852)
at org.exolab.castor.xml.Marshaller.marshal(Marshaller.java:1852)
at org.exolab.castor.xml.Marshaller.marshal(Marshaller.java:1835)
at org.exolab.castor.xml.Marshaller.marshal(Marshaller.java:842)
at
TestXMLBindingFrameworks.testCastor(TestXMLBindingFrameworks.java:86)
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
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:478)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:344)
at
org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:196)
Shouldn't the following XML element make Castor to look for ClientDcl
object's ID??
<bind-xml name="ClientGUID" node="element"
type="com.adminserver.dcl.ClientDcl"
reference="true"/>
But instead it is trying to lookup the ID for java.lang.String as per
the following declaration in the ClientFieldDcl mapping:
<field name="clientGuid" type="string"
get-method="getClientGuid"
set-method="setClientGuid">
Also it sounds like you can use the reference="true" for referencing and
setting the whole object and not just one of it's property! Is that
true?
In this case we just need the clientGuid property of the ClientDcl
object and not the whole ClientDcl object!
I am currently tasked with comparing Jibx (jibx.sf.net), Javolution
(javolution.org) & Castor (castor.sf.net) with regards to Java <-> XML
marshalling/unmarshalling. So far Castor seems to be a clear winner when
it comes to supporting marshalling/unmarshalling most of the Java data
structures with the exception of the above little requirement. The other
solutions require addition of cryptic custom code to just handle say
HashMaps.
--Sandeep Khanna
>
> --Keith
>
>
> -------------------------------------------------
> If you wish to unsubscribe from this list, please
> send an empty message to the following address:
>
> [EMAIL PROTECTED]
> -------------------------------------------------
>
-------------------------------------------------
If you wish to unsubscribe from this list, please
send an empty message to the following address:
[EMAIL PROTECTED]
-------------------------------------------------