【问题标题】:JAXB override @XmlElement type of listJAXB 覆盖 @XmlElement 类型的列表
【发布时间】:2016-07-13 09:44:33
【问题描述】:

有一个简单的类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 的子级。

那么,我怎样才能强制它用BeanChild2 实例填充childList 字段?

如果没有简单的解决方案,请随时发布更多有创意的解决方案(例如使用XmlAdapters、Unmarshaller.Listener,也许在父类或子类上附加注释......)

【问题讨论】:

    标签: java jaxb unmarshalling xmladapter


    【解决方案1】:

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

    • 无论您使用什么@XmlAccessorType(例如FIELDPROPERTYPUBLICNONE)都没有关系。
    • 将注释放在字段或 getter 上没有任何区别。

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

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

    <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) 注释被替换为等同于@XmlElement(name=child, type=BeanChild2.class) 的xml 定义。

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-06-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-08-19
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多