Like the title says, I have two different objects that implement the same interface and I want to add them to the same collection.
My XML looks like:
<root>
<item-list>
<item>
<type1>
<id>1</id>
</type1>
</item>
<item>
<type2>
<id>2</id>
<other>1</other>
</type2>
</item>
</item-list>
</root>
The tag under item
can either be type1
or type2
at any time. They have similar values but, as you see, type2
has another field.
My Interface is:
public interface Item {
public String getID();
}
My three classes:
public class MyObj {
private ArrayList<Item> items = new ArrayList<Item>();
public List<Item> getItems() {
return items;
}
}
public class Type1 implements Item{
private String id;
@Override
public String getID() {
return id;
}
}
public class Type2 implements Item {
private String id;
private String other;
@Override
public String getID() {
return id;
}
public String getOther() {
return other;
}
}
My binding looks like this:
<binding direction="input" >
<mapping name="item-list" class="jibx.woe.MyObj" >
<collection field="items" >
<structure name="item" choice="true" ordered="false">
<structure name="type1" map-as="type1"/>
<structure name="type2" map-as="type2"/>
</structure>
</collection>
</mapping>
<mapping class="jibx.woe.Type1" abstract="true" type-name="type1">
<value name="id" field="id"/>
</mapping>
<mapping class="jibx.woe.Type2" abstract="true" type-name="type2">
<value name="id" field="id"/>
<value name="other" field="other"/>
</mapping>
And when I run it, I get the this error:
*** Error during code generation for file 'C:\Projects\IdeaProjects\jibx-woe\src \main\config\woe-binding.xml' -
this may be due to an error in your binding or classpath, or to an error in the JiBX code ***
Internal error: Expected jibx.woe.Type1 on stack, found java.lang.Object full stack:
0: java.lang.Object
1: java.lang.Object
2: org.jibx.runtime.impl.UnmarshallingContext
So I thought I add an item type to the collection, so now my collection section looks like:
<collection field="items" item-type="jibx.woe.Item">
<structure name="item" choice="true" ordered="false" >
<structure name="type1" map-as="type1"/>
<structure name="type2" map-as="type2"/>
</structure>
</collection>
And the error now says:
Internal error: Expected jibx.woe.Type1 on stack, found jibx.woe.Item
full stack:
0: jibx.woe.Item
1: jibx.woe.Item
2: org.jibx.runtime.impl.UnmarshallingContext
So now I add the following method to MyObj
:
public void addItem(Object type) {
items.add((Item)type);
}
And changed the collection
tag to:
<collection add-method="addItem">
And get same same error as my first attempt:
Internal error: Expected jibx.woe.Type1 on stack, found java.lang.Object
full stack:
0: java.lang.Object
1: java.lang.Object
2: org.jibx.runtime.impl.UnmarshallingContext
And now I'm out of ideas. How can I get this to work?
EDIT
Based on Archie's recommendation below, I changed my binding to:
<mapping name="root" class="jibx.woe.MyObj">
<structure name="item-list" >
<collection field="items">
<structure name="item" /> >
</collection>
</structure>
</mapping>
<mapping name="type1" class="jibx.woe.Type1" >
<value name="id" field="id"/>
</mapping>
<mapping name="type2" class="jibx.woe.Type2" >
<value name="id" field="id"/>
<value name="other" field="other"/>
</mapping>
</binding>
And now the binding works without stack errors (hurray!) but now when I get a item from my list a la:
List<Item> items = woe.getItems();
Type1 item = (Type1) items.get(0);
I get:
java.lang.ClassCastException: java.lang.Object cannot be cast to jibx.woe.Type1
On my second line above. If I print the object: System.out.println(items.get(0));
It says: java.lang.Object@1be2d65
So it's a plain object, not an Element or a Type1 (or Type2) at all!
I did try the "extends" method Archie proposed, but it didn't change anything -- I got the same result.