I've been using Castor for a while, but don't consider myself an expert by
any means.
I would appreciate some help with this problem - can anyone tell me what I'm
doing wrong, please?
Apologies for the length of the message: I've put a summary of the problem
at the top, followed by an example which demonstrates what's going wrong.
For the record, I'm using Castor 0.9.5.3 and Java 1.4.2_04.
I'm having trouble when I try to use a Marshaller with a namespace mapping
set through the setNamespaceMapping(String, String) method.
If I have a field which holds an instance of another class (a class which is
described in the mapping file), I get problems when the name attribute of
the field's <bind-xml> tag is not the same as the xml attribute of the
target class's <map-to> tag. I get the following error:
org.xml.sax.SAXException: unable to find FieldDescriptor for 'fieldName' in
ClassDescriptor of className
If I comment out the call to setNamespaceMapping everything works fine, but
unfortunately I need that call in so the resultant marshalled xml can be
opened in Internet Explorer.
Another way of solving it is to make sure the <bind-xml> name attribute is
set to the <map-to> xml attribute's value of the target class, but that's
not going to be possible if (for example) the source class needs two fields
both of the type of that target class.
I created a small example to illustrate the problem, which I have included
below. Obviously it's rather contrived!
First, the classes I'm using:
Marble.java:----------------------------------------
public class Marble implements IMarble {
public Marble() {
}
public String getColour() {
return _colour;
}
public void setColour(String colour) {
_colour = colour;
}
public int hashCode() {
return _colour.hashCode();
}
public boolean equals(Object obj) {
return obj instanceof Marble && _colour.equals(((Marble)
obj)._colour);
}
private String _colour;
}
----------------------------------------------------
MarbleContainer.java:-------------------------------
public class MarbleContainer {
public MarbleContainer() {
}
public IMarble getMyMarble() {
return _marble;
}
public void setMyMarble(IMarble marble) {
_marble = marble;
}
public String getOwnerName() {
return _ownerName;
}
public void setOwnerName(String ownerName) {
_ownerName = ownerName;
}
public int hashCode() {
return _ownerName.hashCode() + _marble.hashCode();
}
public boolean equals(Object obj) {
if (obj instanceof MarbleContainer) {
MarbleContainer marbleContainer = (MarbleContainer) obj;
return _marble.equals(marbleContainer._marble) &&
_ownerName.equals(marbleContainer._ownerName);
}
return false;
}
private String _ownerName;
private IMarble _marble;
}
----------------------------------------------------
I'm using the following mapping file:---------------
<mapping>
<class name="Marble">
<map-to table="no-table"
xml="marble"
ns-prefix="marb" />
<cache-type type="count-limited" />
<field name="colour"
type="string"
required="true"
get-method="getColour"
set-method="setColour">
<bind-xml name="colour"
node="attribute" />
</field>
</class>
<class name="MarbleContainer">
<map-to table="no-table"
xml="marble-container"
ns-prefix="marb" />
<cache-type type="count-limited" />
<field name="ownerName"
type="string"
required="true"
get-method="getOwnerName"
set-method="setOwnerName">
<bind-xml name="owner-name"
node="attribute" />
</field>
<field name="myMarble"
type="IMarble"
required="true"
get-method="getMyMarble"
set-method="setMyMarble">
<bind-xml name="my-marble"
node="element" />
</field>
</class>
</mapping>
----------------------------------------------------
Note that the bind-xml name attribute is "my-marble" but the map-to xml
attribute of the Marble class's mapping is "marble".
I also have a MarbleContainerMarshaller which wraps up the marshalling and
unmarshalling process.
MarbleContainerMarshaller.java:------------[extract]
public void marshalMarbleContainer(Writer writer, MarbleContainer
marbleContainer) throws Exception {
Marshaller marshaller = getMarshaller(writer);
marshaller.marshal(marbleContainer);
}
public MarbleContainer unmarshal(Reader reader) throws Exception {
Unmarshaller unmarshaller = getUnmarshaller();
MarbleContainer marbleContainer = (MarbleContainer)
unmarshaller.unmarshal(reader);
return marbleContainer;
}
private Unmarshaller getUnmarshaller() throws MappingException {
Unmarshaller unmarshaller = new Unmarshaller((Class) null);
unmarshaller.setResolver(_classDescriptorResolver);
unmarshaller.setMapping(_mapping);
ClassLoader classLoader = getClassLoader();
unmarshaller.setClassLoader(classLoader);
return unmarshaller;
}
private Marshaller getMarshaller(Writer writer) throws IOException,
MappingException {
Marshaller marshaller = new Marshaller(writer);
marshaller.setResolver(_classDescriptorResolver);
marshaller.setNamespaceMapping("marb",
"http://www.marbles.com/marbles");
marshaller.setMapping(_mapping);
marshaller.setDebug(false);
return marshaller;
}
private ClassLoader getClassLoader() {
ClassLoader classLoader =
Thread.currentThread().getContextClassLoader();
if (classLoader == null) {
classLoader = getClass().getClassLoader();
}
return classLoader;
}
----------------------------------------------------
Finally I have a main method which creates a Marble and a MarbleContainer
and sets the Marble on the MarbleContainer. It then marshals the
MarbleContainer to an xml file, and tries to unmarshal it back using the
following piece of code:
Application.java---------------------------[extract]
FileWriter writer = new FileWriter(marbleFile);
MarbleContainerMarshaller marshaller = new
MarbleContainerMarshaller();
marshaller.marshalMarbleContainer(writer, marbleContainer);
writer.close();
FileReader reader = new FileReader(marbleFile);
MarbleContainer unmarshalledMarbleContainer =
marshaller.unmarshal(reader);
if (marbleContainer.equals(unmarshalledMarbleContainer)) {
System.out.println("MarbleContainers are equal");
}
else {
System.out.println("MarbleContainers are NOT equal");
}
----------------------------------------------------
If the setNamespaceMapping line in MarbleContainerMarshaller.getMarshaller
is present, I get the error 'org.xml.sax.SAXException: unable to find
FieldDescriptor for 'my-marble' in ClassDescriptor of marble-container'. If
I comment out the setNamespaceMapping line, the process succeeds and the
unmarshalled MarbleContainer equals the original one I marshalled out.
I have tried changing the value of the 'org.exolab.castor.parser.namespaces'
property in castor.properties but whether it's true or false doesn't seem to
help.
I imagine I'm doing something horribly wrong, but I honestly can't see what
it is!
Any ideas?
Many thanks for any help you can give!
Yours,
Alistair Sheffield
-----------------------------------------------------------
If you wish to unsubscribe from this mailing, send mail to
[EMAIL PROTECTED] with a subject of:
unsubscribe castor-user