JAXB覆盖@XmlElement类型的列表

时间:2016-07-13 09:44:34

标签: java jaxb unmarshalling xmladapter

有一个简单的类Bean1,其子列表类型为BeanChild1

@XmlRootElement(name="bean")
@XmlAccessorType(XmlAccessType.PROPERTY)
public static class Bean1
{
  public Bean1()
  {
    super();
  }

  private List<BeanChild1> childList = new ArrayList<>();

  @XmlElement(name="child")
  public List<BeanChild1> getChildList()
  {
    return childList;
  }

  public void setChildList(List<BeanChild1> pChildList)
  {
    childList = pChildList;
  }
}

public static class BeanChild1 { ... }

我试图覆盖该类,以更改列表的类型。 新的子类(即BeanChild2)扩展了前一个(即BeanChild1)。

public static class Bean2 extends Bean1
{
  public Bean2()
  {
    super();
  }

  @Override
  @XmlElement(name="child", type=BeanChild2.class)
  public List<BeanChild1> getChildList()
  {
    return super.getChildList();
  }
}

public static class BeanChild2 extends BeanChild1 { }

所以,这是我测试它的方式:

public static void main(String[] args)
{
  String xml = "<bean>" +
               "  <child></child>" +
               "  <child></child>" +
               "  <child></child>" +
               "</bean>";
  Reader reader = new StringReader(xml);

  Bean2 b2 =  JAXB.unmarshal(reader, Bean2.class);
  assert b2.getChildList().get(0) instanceof BeanChild2; // fails
}

测试显示此列表仍包含BeanChild1的孩子。

那么,如何强制它使用childList个实例填充BeanChild2字段?

如果没有简单的解决方案,请随时发布更具创意的解决方案(例如,使用XmlAdapter s,Unmarshaller.Listener,或许在父类或子类上添加其他注释...)

1 个答案:

答案 0 :(得分:0)

无法更改(例如覆盖)超类的@XmlElement注释。至少不使用注释。

  • 您使用@XmlAccessorType的内容并不重要(例如FIELDPROPERTYPUBLICNONE)。
  • 如果将注释放在字段或getter上,则没有任何区别。

然而,有一个合理的选择。 JAXB的MOXy实现提供define the metadata/bindings in an xml file的能力。事实上,每个java注释都有一个XML替代方案。但它会变得更好:你可以将java注释和这些xml元数据结合起来。很酷的是,MOXy会合并两个声明,如果发生冲突, XML定义的元数据会得到一个更高的优先级。

假设Bean1类注释如上。然后可以在xml文件中重新定义绑定。 e.g:

<xml-bindings xml-accessor-type="PROPERTY">
  <java-types>
    <java-type name="Bean1">
      <xml-element java-attribute="childList" name="child" 
                   type="BeanChild2" container-type="java.util.ArrayList" />
    </java-type>
  </java-types>
</xml-bindings>

在创建上下文对象时需要这个新的绑定文件。

// use a map to reference the xml file
Map<String, Object> propertyMap = new HashMap<>();
propertyMap.put(JAXBContextProperties.OXM_METADATA_SOURCE, "bindings.xml");

// pass this properyMap during the creation of the JAXB context.
JAXBContext context = JAXBContext.newInstance(..., propertyMap);

MOXy将合并java注释和XML绑定,如果发生冲突,则应用XML定义的设置。在这种情况下,较早的@XmlElement(name=child)注释被xml定义替换,该定义等同于@XmlElement(name=child, type=BeanChild2.class)

您可以阅读有关XML绑定here的更多信息。