如何让Jibx在集合中添加两个实现相同接口的不同对象?

时间:2010-08-27 18:36:05

标签: java xml 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下的标记可以随时type1type2。它们具有相似的值,但如您所见,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>

现在绑定工作没有堆栈错误(欢呼!)但现在当我从列表中得到一个项目时la:

    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)!

我确实尝试了Archie提出的“扩展”方法,但它没有改变任何东西 - 我得到了相同的结果。

1 个答案:

答案 0 :(得分:1)

为Item创建抽象映射。然后为Type1和Type2创建两个具体映射,每个映射都扩展Item映射。在你的items集合中,将每个元素设为一个Item(摆脱选择的东西)。

注意在JiBX中,'extends'关键字与Java类无关,它意味着'可以替代'。

限制:您必须为Type1和Type2提供两个不同的XML标记名称(例如,“type1”和“type2”),以便JiBX在解组时可以区分它们。这是您目前正在做的问题。例如,当JiBX看到一个标签时,它将如何知道要实例化哪个Java类?