如何让 Jibx 在集合中添加两个实现相同接口的不同对象?
就像标题所说,我有两个实现相同接口的不同对象,我想将它们添加到同一个集合中。
我的 XML 如下所示:
<root>
<item-list>
<item>
<type1>
<id>1</id>
</type1>
</item>
<item>
<type2>
<id>2</id>
<other>1</other>
</type2>
</item>
</item-list>
</root>
item
下的标记可以随时为 type1
或 type2
。它们具有相似的值,但如您所见,type2
还有另一个字段。
我的界面是:
public interface Item {
public String getID();
}
我的三个类:
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;
}
}
我的绑定如下所示:
<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>
当我运行它时,我收到此错误:
*** 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
所以我以为我向集合中添加了一个项目类型,所以现在我的集合部分看起来像:
<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>
现在错误显示:
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
所以现在我将以下方法添加到 MyObj
:
public void addItem(Object type) {
items.add((Item)type);
}
并将 collection
标记更改为:
<collection add-method="addItem">
并得到与我第一次尝试相同的错误:
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
现在我没有主意了。我怎样才能让它发挥作用?
编辑
根据下面Archie的建议,我将绑定更改为:
<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>
现在绑定工作没有堆栈错误(万岁!)但是现在当我从列表中获取一个项目时:
List<Item> items = woe.getItems();
Type1 item = (Type1) items.get(0);
我得到:
java.lang.ClassCastException: java.lang.Object cannot be cast to jibx.woe.Type1
在上面的第二行。如果我打印该对象: System.out.println(items.get(0));
它说: java.lang.Object@1be2d65
所以它是一个普通对象,根本不是 Element 或 Type1(或 Type2)!
我确实尝试了阿奇提出的“扩展”方法,但它没有改变任何东西——我得到了相同的结果。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
为 Item 创建抽象映射。然后为 Type1 和 Type2 创建两个具体映射,每个映射都扩展 Item 映射。在您的项目集合中,使每个元素成为一个项目(去掉选择的东西)。
请注意,在 JiBX 中,“extends”关键字与 Java 类无关,它的意思是“可以替代”。
限制:您必须为 Type1 和 Type2 提供两个不同的 XML 标记名称(例如“type1”和“type2”),以便 JiBX 在解组时可以区分它们。这是你目前所做的事情的问题。例如,当 JiBX 看到一个标签时,它如何知道要实例化哪个 Java 类?
Create an abstract mapping for Item. Then create two concrete mappings for Type1 and Type2, each extending the Item mapping. In your items collection, make each element an Item (get rid of the choice stuff).
Note in JiBX the 'extends' keyword has nothing to do with Java classes, it means 'can be substituted for'.
Limitation: you will have to give Type1 and Type2 two different XML tag names (e.g., "type1" and "type2") so JiBX can distinguish them when unmarshalling. This is the problem with what you are currently doing. E.g., when JiBX sees an tag, how will it know which Java class to instantiate?