Hi Vairoj,
The problem with the approach you're taking of using a
serializer/deserializer is that ser/desers only handle converting an
object or primitive value to and from a /text/ representation. They give
no control over the element name. To control the element name based on
the type of object you need to either list the choices as alternatives
or use a custom marshaller/unmarshaller for that particular element.
Here's an example of how you could structure this to list the choices as
alternative:
<mapping name="item" class="...EquipmentLineItem">
<structure field="equipment">
<structure name="phone" type="...Phone"
factory="...phoneFactoryMethod" usage="optional">
<structure map-as="...Equipment"/>
</structure>
<structure name="pda" type="...Pda" factory="...pdaFactoryMethod"
usage="optional">
<structure map-as="...Equipment"/>
</structure>
</structure>
<value name="quantity" field="quantity"/>
</mapping>
This may be getting into some unexplored territory in the validation and
code generation, so I won't guarantee that it will work. But in theory
it should be a valid binding. With the RC1 code you'd need to use a
specific factory for each type; with RC2 you'd be able to use a single
factory method that just returned a common supertype, which would then
be cast to the appropriate type at runtime.
To instead use a custom marshaller/unmarshaller, you'd just set the
marshaller and unmarshaller:
<mapping name="item" class="...EquipmentLineItem">
<structure field="equipment" marshaller="...EquipmentMarshaller"
unmarshaller="...EquipmentUnmarshaller"/>
<value name="quantity" field="quantity"/>
</mapping>
Your marshaller code can then determine the element name to be written
based on the actual type of the equipment passed in, while the
unmarshaller just looks up the equipment instance to be returned based
on the element name and data value. This takes a little more work on
your part than handling the choices in the binding, but is probably
cleaner and uses code that has been more thoroughly tested.
- Dennis
Vairoj A. wrote:
Hi Dennis,
I might not explain my needs clearly in my previous post. So let me
clarify it.
The unmarshalling process does not create new instance of Equipment,
but rather link to a previously created one. As you can see from the
sample XML file.
<equipment>
<item>
<phone>Siemens S45</phone>
<quantity>5</quantity>
</item> <item>
<pda>O2 XDA</pda>
<quantity>2</quantity>
</item>
</equipment>
It only describes what type of Equipment each line item associated
with, but not all attributes of each Equipment to construct it (those
someOtherAttrib are not in the XML file). This information will be use
to creates association in EquipmentLineItem object to reference to a
suitable Equipment object - which is already created. This mechanism
is provided by a factory method. That is why I ends up using
serializer and deserializer.
The name attributes in each Equipment instances is required, as it
described the specific unique name of each equipment, not just a type.
For example, I might have an instance of Phone (Phone is a type of
Equipment) with "Siemens S45" as name.
Now I defined the mapping for EquipmentLineItem as follow:
<mapping name="EquipmentLineItem"
class="com.waveman.poc.EquipmentLineItem">
<value name="name" field="equipment"
serializer="com.waveman.poc.BindingUtils.toString"
deserializer="com.waveman.poc.BindingUtils.findEquipment"
/>
<value name="quantity" field="quantity" />
</mapping>
Using this mapping achieve my needs, except that element name for
Equipment will always be <name> no matter what type of the equipment is.
What if I want element name of each Equipment type to be different? So
instead of generic <name> tag, I would have <phone>Siemens S45</phone>
for Phone instance and <pda>O2 XDA</pda> for Pda instance. I could not
figure out how to use abstract mapping with the above mapping I
currently have.
Regards,
Vairoj
--__--__--
Message: 4
Date: Fri, 18 Nov 2005 14:06:10 -0800
From: Dennis Sosnoski <[EMAIL PROTECTED]>
To: [email protected]
Subject: Re: [jibx-users] Re: Abstract, structure mapping with
multiple elements
(revised)
Reply-To: [email protected]
Hi Vairoj,
I think the approach you want here is not to use a
serializer/deserializer, but rather to list the alternatives in the
EquipmentLineItem <mapping>. You should be able to use an abstract
mapping for the Equipment class as part of this (though I haven't
tried it, and I'm not sure the value with style="text" inside an
abstract mapping is going to work without a hitch):
<mapping name="lineitem" ...>
<structure name="phone" class="...Phone">
<structure map-as="...Equipment"/>
<value style="attribute" name="someOtherAttrib"
field="someOtherAttrib"/>
</structure>
<structure name="pda" class="...Pda">
<structure map-as="...Equipment"/>
<value style="attribute" name="someOtherAttrib"
field="someOtherAttrib"/>
</structure>
...
</mapping>
<mapping class="...Equipment" abstract="true">
<value style="text" name="name"/>
</mapping>
But the way I'd probably handle this myself is to avoid the name in
the Equipment class all together, instead using an abstract getName()
method. Then Phone just implements this:
class Phone extends Equipment {
public String getName() { return "phone"; }
}
Why have a name field, after all, when you want the name to be
determined by the type of equipment?
- Dennis
Vairoj A. wrote:
Hi,
Sorry for a separate post. After posted the message, I managed to
find a way to provide flatten mapping for Equipment using serializer
and deserializer.
So now I have the binding defined as follow:
<mapping name="lineitem"
class="com.waveman.poc.EquipmentLineItem">
<value name="name"
field="equipment"
serializer="com.waveman.poc.BindingUtils.equipmentToString"
deserializer="com.waveman.poc.BindingUtils.stringToEquipment"
/>
<value name="quantity" field="quantity" />
</mapping>
However, I still could not figure out how to have different element
name based on Equipment subclasses. The current binding always map
Equipment to <name> tag under <lineItem> here is the example (which
is not the correct one).
<equipment>
<lineitem>
<name>Siemens S45</name>
<quantity>10</name>
</lineitem>
<lineitem>
<name>O2 XDA</name>
<quantity>5</quantity>
</equipment>
So now, the revised (and hopefully, final) question is, how to
define the binding to have element name different, based on
subclasses of Equipment (like the example XML file in my previous
post)?
Regards,
Vairoj
Vairoj A. wrote:
Hi,
After my previous post with suggestion from Dennis, I have
re-evaluate the structure of both domain object and XML with other
application requirements. It is confirm the the domain object has
to remain unchanged. However, the XML structure can be changed.
So the same object model:
class Person {
private Set<EquipmentLineItem> lineItems;
}
class EquipmentLineItem {
private Equipment equipment;
private int quantity;
}
abstract class Equipment {
private String name;
}
class Phone extends Equipment {
private int someOtherAttrib;
}
class Pda extends Equipment {
private String someOtherAttrib;
}
Now, the XML will be look like what Dennis suggested in his reply
to my previous post:
<equipment>
<item>
<phone>Siemens S45</phone>
<quantity>5</quantity>
</item> <item>
<pda>O2 XDA</pda>
<quantity>2</quantity>
</item>
</equipment>
Point to note is that, the binding will not construct Equipment
subclass itself this time. As you can see from the class
declaration, there are some other attributes specific to each
subclass. So I would like to delegate the instantiation of
Equipment subclass to a factory method instead. The factory method
returns correct instance (fully initialized) based on String
between <phone> tag or <pda> tag (i.e. Siemens S45, O2 XDA)
public static Equipment getEquipment(String equipmentName)
Based on the above requirements, I am having 2 issues regarding
binding:
1. How can I define the mapping for equipment so that different
subclass map to different element name?
2. I don't seems to make use of factory attribute correctly. While
it use the factory method to create new instance, it still override
values of the instance with one from the XML, which I do not want.
Could you give me a binding example for the situation? I am kind of
stuck now. Thank you very much, I know that the question is not a
short one.
Regards,
Vairoj
-------------------------------------------------------
This SF.Net email is sponsored by the JBoss Inc. Get Certified Today
Register for a JBoss Training Course. Free Certification Exam
for All Training Attendees Through End of 2005. For more info visit:
http://ads.osdn.com/?ad_id=7628&alloc_id=16845&op=click
_______________________________________________
jibx-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jibx-users
-------------------------------------------------------
This SF.net email is sponsored by: Splunk Inc. Do you grep through log files
for problems? Stop! Download the new AJAX search engine that makes
searching your log files as easy as surfing the web. DOWNLOAD SPLUNK!
http://ads.osdn.com/?ad_id=7637&alloc_id=16865&op=click
_______________________________________________
jibx-users mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/jibx-users