On Fri, Mar 31, 2006 at 12:49:59AM -0600, Keith Visco wrote:
> True and we've known about that for a while, and I apologize for not
> having that documentation updated sooner. The container attribute is
> quite talked about on the list however.
No criticism was intended, I was just explaining why I hadn't
done my homework on that option :-). As I said the Castor docs are
pretty good, but I get the feeling I'm missing some of the context,
i.e. things are implied or assumed, that maybe I would catch if I were
more familiar with object mapping tools.
I do appreciate both the code, the docs and the help here on the
list. It could have been a little easier, but I finally tried every
possible combination and now I think I've got it working (well, I
*know* I've got it working, the question is whether I'm doing it the
right way or not).
Steven J. Owens wrote:
>> I tried the obvious, the following in OrderMapping.xml:
>>
>> <field name="Item"
>> type="com.foo.Item"
>> container="true"
>> collection="arraylist">
>> <bind-xml name="Items"/>
>> </field>
>>
>> This got me a java.lang.StackOverflowError.
Keith Visco wrote:
> You want to use container="false" here. You also want to make sure
> you have a mapping for class com.foo.Item such as:
>
> <class name="com.foo.Item">
> <mapTo xml="item"/>
> ...
> </class>
Whoops, missed that.
Okay, first the good news; I applied this advice and it works
with the enclosing <Items> tag (yay!). The (working) mappings now
look like:
--OrderMapping.xml--
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<include href="CustomerMapping.xml"/>
<include href="ItemMapping.xml"/>
<class name="com.foo.Order">
<field name="WrapperDetail" type="string" transient="true">
<bind-xml name="WrapperDetail"/>
</field>
<field name="instanceCustomer" type="com.foo.Customer">
<xml bind-to="Customer"/>
</field>
<field name="instanceItems" type="com.foo.Item" container="false"
collection="arraylist">
<bind-xml name="Items"/>
</field>
</class>
</mapping>
--------------------
--ItemMapping.xml---
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="com.foo.Item">
<map-to xml="Item"/>
<field name="instanceSku" type="string" node="text">
<bind-xml name="Sku"/>
</field>
<field name="instanceDescription" type="string" node="text">
<bind-xml name="Description"/>
</field>
<field name="instanceManufacturer" type="string" node="text">
<bind-xml name="Manufacturer"/>
</field>
</class>
</mapping>
--------------------
Now for CustomerWrapper:
Steven J. Owens wroet:
>>According to the docs, I should be able ignore <CustomerWrapper> by
>>specifying the fields like:
>>
>> <field name="recipient"
>> type="String"
>> location="CustomerWrapper"
>> node="text">
>> <bind-xml name="Recipient"/>
>> </field>
Stephen Bash wrote:
>> To address some of your specific issues. I agree CustomerWrapper
>> should be mapped using the location attribute. Why it doesn't work is
>> something else.
Keith Visco wrote:
> It's not working because the location="CustomerWrapper" needs to be on
> the <bind-xml> element and not the <field> element.
Doh... okay, good point, maybe putting on the right element would
help :-). Well, as it turns out, it did, but figuring out _which_
<bind-xml> to use was a bit tricky. I ended up trying every
permutation between the Order mapping and Customer mapping. I tried
it in the bind-xml tags inside CustomerMapping.xml. I tried it on the
bind-xml tag for the Customer field inside OrderMapping.xml. I tried
it in both.
What finally did the trick was swapping Customer and
CustomerWrapper inside CustomerMapping.xml. So now the Customer class
is mapped to <CustomerWrapper> and each field is pulled from the
internal <Customer> tag set. I still can't help feeling there's a
"right" (better, or perhaps cleaner) way to do this, but that's what I
have working now.
And I now when I add back in the WrapperDetail with
transient="true", it gets ignored. Or I could uncomment the
setIgnoreExtraElements(true) in UnmarshallerTest.java.
For posterity, here's the complete set of files. Maybe these
would make a good tutorial.
--OrderMapping.xml--
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<include href="CustomerMapping.xml"/>
<include href="ItemMapping.xml"/>
<class name="com.foo.Order">
<field name="instanceCustomer" type="com.foo.Customer">
<xml bind-to="Customer"/>
</field>
<field name="instanceItems" type="com.foo.Item" container="false"
collection="arraylist">
<bind-xml name="Items"/>
</field>
</class>
</mapping>
--------------------
--CustomerMapping.xml--
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="com.foo.Customer">
<map-to xml="CustomerWrapper"/>
<field name="WrapperDetail" type="string" transient="true">
<bind-xml name="WrapperDetail"/>
</field>
<field name="instanceRecipient" type="string" node="text">
<bind-xml name="Recipient" location="Customer"/>
</field>
<field name="instanceAddress" type="string" node="text">
<bind-xml name="Address" location="Customer"/>
</field>
<field name="instanceZipCode" type="string" node="text">
<bind-xml name="ZipCode" location="Customer"/>
</field>
</class>
</mapping>
--------------------
--ItemMapping.xml---
<?xml version="1.0"?>
<!DOCTYPE mapping PUBLIC "-//EXOLAB/Castor Mapping DTD Version 1.0//EN"
"http://castor.org/mapping.dtd">
<mapping>
<class name="com.foo.Item">
<map-to xml="Item"/>
<field name="instanceSku" type="string" node="text">
<bind-xml name="Sku"/>
</field>
<field name="instanceDescription" type="string" node="text">
<bind-xml name="Description"/>
</field>
<field name="instanceManufacturer" type="string" node="text">
<bind-xml name="Manufacturer"/>
</field>
</class>
</mapping>
--------------------
--OrderExample.xml--
<Order>
<CustomerWrapper>
<WrapperDetail>uselessValue</WrapperDetail>
<Customer>
<Recipient>Bob</Recipient>
<Address>123 Public Street</Address>
<ZipCode>11111111</ZipCode>
</Customer>
</CustomerWrapper>
<Items>
<Item>
<Sku>1</Sku>
<Description>soap</Description>
<Manufacturer>Irish Spring</Manufacturer>
</Item>
<Item>
<Sku>2</Sku>
<Description>towel</Description>
<Manufacturer>Sears</Manufacturer>
</Item>
<Item>
<Sku>3</Sku>
<Description>bathrobe</Description>
<Manufacturer>Polo</Manufacturer>
</Item>
<!-- ...repeat Item tags ad nauseam... -->
</Items>
</Order>
--------------------
And, since I hate it when I find a post in the archive that
clearly is somebody trying to solve the problem I'm struggling with,
only the poster didn't include enough details in the final message to
reconstruct what solved it, here's the java source, just to leave
nothing to chance for future list-archive readers:
--/com/foo/UnmarshallerTest.java--
package com.foo ;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.util.Iterator;
import java.util.List ;
import org.exolab.castor.mapping.Mapping;
import org.exolab.castor.mapping.MappingException;
import org.exolab.castor.xml.MarshalException;
import org.exolab.castor.xml.Unmarshaller;
import org.exolab.castor.xml.ValidationException;
public class UnmarshallTest {
public static void main(String[] args) {
String rootDir = "./castortest/working/" ;
String dataFileName = "OrderExample.xml" ;
String mappingFileName = "OrderMapping.xml" ;
if (0 < args.length) {
rootDir = args[0] ;
}
UnmarshallTest test = new UnmarshallTest() ;
test.test(rootDir + dataFileName, rootDir + mappingFileName) ;
}
public void test(String dataFileName, String mappingFileName) {
try {
File dataFile = new File(dataFileName) ;
Reader dataReader = new FileReader(dataFile) ;
Mapping testMapping= new
org.exolab.castor.mapping.Mapping();
System.out.println("Reading sample data from \"" +
dataFileName + "\"") ;
System.out.println("Loading mapping from \"" +
mappingFileName + "\"") ;
testMapping.loadMapping(mappingFileName);
Unmarshaller unmarshaller = new
Unmarshaller(Order.class);
// unmarshaller.setIgnoreExtraElements(true) ;
unmarshaller.setMapping(testMapping);
Order order =
(Order)(unmarshaller.unmarshal(dataReader));
System.out.println("" + order) ;
} catch (MarshalException e) {
e.printStackTrace() ;
throw new RuntimeException("Castor Marshal Exception") ;
} catch (MappingException e) {
e.printStackTrace();
throw new RuntimeException("Castor Mapping Exception") ;
} catch (ValidationException e) {
e.printStackTrace() ;
throw new RuntimeException("XML Validation Exception") ;
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("IOexception") ;
}
}
}
-------------------------
--/com/foo/Order.java----
package com.foo ;
import java.util.Iterator ;
import java.util.List ;
import java.util.ArrayList ;
public class Order {
private Customer instanceCustomer ;
public Customer getInstanceCustomer() {
return this.instanceCustomer ;
}
public void setInstanceCustomer(Customer customer) {
this.instanceCustomer = customer ;
}
private List instanceItems ;
public List getInstanceItems() {
return this.instanceItems ;
}
public void setInstanceItems(List items) {
this.instanceItems = items ;
}
// Singular version for Castor
public List getInstanceItem() {
return this.instanceItems ;
}
public String toString() {
StringBuffer buf = new StringBuffer() ;
buf.append("" + getInstanceCustomer()) ;
if (null == getInstanceItems()) {
buf.append("Items list is null.") ;
return buf.toString() ;
}
if (getInstanceItems().isEmpty()) {
buf.append("Items list is empty.") ;
return buf.toString() ;
}
Iterator it = getInstanceItems().iterator() ;
while (it.hasNext()) {
buf.append("----\n") ;
buf.append("" + (Item)it.next()) ;
}
return buf.toString() ;
}
}
-------------------------
--/com/foo/Customer.java--
package com.foo ;
public class Customer {
private String instanceRecipient ;
private String instanceAddress ;
private String instanceZipCode ;
public String getInstanceRecipient() {
return this.instanceRecipient ;
}
public void setInstanceRecipient(String recipient) {
this.instanceRecipient = recipient ;
}
public String getInstanceAddress() {
return this.instanceAddress ;
}
public void setInstanceAddress(String address) {
this.instanceAddress = address ;
}
public String getInstanceZipCode() {
return this.instanceZipCode ;
}
public void setInstanceZipCode(String zipCode) {
this.instanceZipCode = zipCode ;
}
public String toString() {
return "Recipient: " + getInstanceRecipient() + "\n"
+ "Address: " + getInstanceAddress() + "\n"
+ "ZipCode: " + getInstanceZipCode() + "\n" ;
}
}
--------------------------
--/com/foo/Item.java------
package com.foo ;
public class Item {
private String instanceSku ;
private String instanceDescription ;
private String instanceManufacturer ;
public String getInstanceSku() {
return this.instanceSku ;
}
public void setInstanceSku(String sku) {
this.instanceSku = sku ;
}
public String getInstanceDescription() {
return this.instanceDescription ;
}
public void setInstanceDescription(String description) {
this.instanceDescription = description ;
}
public String getInstanceManufacturer() {
return this.instanceManufacturer ;
}
public void setInstanceManufacturer(String manufacturer) {
this.instanceManufacturer = manufacturer ;
}
public String toString() {
return "Sku: " + getInstanceSku() + "\n"
+ "Description: " + getInstanceDescription() + "\n"
+ "Manufacturer: " + getInstanceManufacturer() + "\n" ;
}
}
-------------------------
--
Steven J. Owens
[EMAIL PROTECTED]
"I'm going to make broad, sweeping generalizations and strong,
declarative statements, because otherwise I'll be here all night and
this document will be four times longer and much less fun to read.
Take it all with a grain of salt." - http://darksleep.com/notablog
-------------------------------------------------
If you wish to unsubscribe from this list, please
send an empty message to the following address:
[EMAIL PROTECTED]
-------------------------------------------------