Details
Description
If you marshal a HashMap that has values that are themselves collections or arrays (see #1175 for this problem related to String[]), the marshalling works, but Castor cannot unmarshall what it creates. A mapping that looks like the following should allow a Collection value:
<mapping>
<class name="Outer" auto-complete="false" >
<map-to xml="outer"/>
<field name="theMap" collection="map">
<bind-xml name="map-name" node="element">
<class name="org.exolab.castor.mapping.MapItem">
<field name="key" type="string"/>
<field name="value" collection="collection"/>
</class>
</bind-xml>
</field>
</class>
</mapping>
However, Castor complains that:
The return type for method public java.lang.Object org.exolab.castor.mapping.MapItem.getValue() does not match the declared field type java.util.Collection
Without the collection attribute on the field mapping, Castor complains that:
element "value" occurs more than once.
To workaround this issue, I created a class like MapItem, called MapCollectionItem (attached), that had:
Collection value;
Collection getValue()
void setValue( Collection val )
{ value = val; }and I added support for using this class where MapItem is used now, when the value is a collection. Changes were to:
org.exolab.castor.mapping.loader.J1CollectionHandlers.java
org.exolab.castor.mapping.loader.J2CollectionHandlers.java
org.exolab.castor.xml.Marshaller.java
org.exolab.castor.xml.UnmarshalHandler.java
I also think a change is needed in test code GACollections.
After this, the marshalled class included the MapCollectionItem reference, but the unmarshall still failed with "element "value" occurs more than once." I tracked this to being a problem where the XMLFieldDescriptor for the value field in the Unmarshaller had the _multivalued flag set to false, even though the collection attribute is set in the field mapping, and the XMLFieldDescriptor for the value field when loading the mapping file has _multivalued set correctly to true. To work around this, I added the following hack to UnmarshalHandler.endElement, around line 729 in the 0.9.9.1 version:
/****** HACK! HACK! HACK! *************/
// I cannot get Castor to handle List values in a HashMap.
// I added support for a MapCollectionItem similar to MapItem, but
// the XLFieldDescriptor has _multivalued false when it should be true.
// I could not figure out why, so I override it here.
if( ! descriptor.isMultivalued() ) {
if( descriptor instanceof XMLFieldDescriptorImpl ) {
if( ((XMLFieldDescriptorImpl)descriptor).getFieldType() == Collection.class )
}
}
/****** end HACK! HACK! HACK! *************/
With these changes, I can unmarshal a List value from a HashMap. I do not pretend that my workaround is a fix to the codebase for this problem, as it is ugly and does not handle all multivalued HashMap values (e.g. #1175 would require a different MapItem class for each array type)
Issue Links
- is related to
-
CASTOR-1551
Mapping of a map with a nested map
-
- relates to
-
CASTOR-1175
Castor cannot unmarshal its own marshalling of a HashMap containing a String[]
-
Failing test case added in bug1313.zip. May need to alter mapping xml file path to run.