继承和JAXB如何结合使用?

14
public abstract class Parent<T> {
    protected List<T> list;

    @XmlTransient   //Question why do we have to give this here?
    public abstract List<T> getList();
    public abstract void setList(List<T> list);
}

@XmlRootElement(name = "child1")
class Child1 extends Parent<ExtendedElement1>{
    @Override
    public void setList(List<ExtendedElement1> list){
        this.list = list;
    }

    @Override
    @XmlElementWrapper(name = "child1-list")
    @XmlElement(name = "child-list-element")
    public List<ExtendedElement1> getList(){
        return this.list;
    }
}

@XmlRootElement(name = "child2")
class Child2 extends Parent<ExtendedElement2>{
    @Override
    public void setList(List<ExtendedElement2> list){
        this.list = list;
    }

    @Override
    @XmlElementWrapper(name = "child1-list")
    @XmlElement(name = "child-list-element")
    public List<ExtendedElement2> getList(){
        return this.list;
    }
}


class Element{
    @XmlElement(name = "integer", type = int.class)
    private int i = 2;
}

class ExtendedElement1 extends Element{
    @XmlElement(name = "extended-element1-str", type = String.class)
    private String str = "hello";
}

class ExtendedElement2 extends Element{
    @XmlElement(name = "extended-element2-str", type = String.class)
    private String str1 = "hello_there";
}

正如我在示例中展示的那样,当我从Parent类的getList()方法中移除@XmlTransient时,以下xml将被编组:

<child1>
<!-- List is serialized 2 times -->
    <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="extendedElement1">
        <integer>2</integer>
        <extended-element1-str>hello</extended-element1-str>
    </list>
    <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="extendedElement1">
        <integer>2</integer>
        <extended-element1-str>hello</extended-element1-str>
    </list>
    <list xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="extendedElement1">
        <integer>2</integer>
        <extended-element1-str>hello</extended-element1-str>
    </list>
    <child1-list>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
    </child1-list>
</child1>

但是当我添加 @XmlTransient 注释,就像这个例子一样,xml 就会按照要求序列化为只包含一个列表。

<child1>
    <child1-list>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
        <child-list-element>
            <integer>2</integer>
            <extended-element1-str>hello</extended-element1-str>
        </child-list-element>
    </child1-list>
</child1>

所以,可以有人解释一下为什么需要在父类的getter方法中加上@XmlTransient?继承和JAXB在这些情况下是如何相互关联的?

1个回答

9

为什么会发生这种情况

JAXB (JSR-222) 的实现将把它所知道的每个域对象映射到一个复杂类型。这意味着它认为在 Parent 类(当 list 不是 @XmlTransient)中存在以下 XML 类型。

  <xs:complexType name="parent" abstract="true">
    <xs:sequence>
      <xs:element name="list" type="xs:anyType" nillable="true" minOccurs="0" maxOccurs="unbounded"/>
    </xs:sequence>
  </xs:complexType>

现在Child2也有一个复杂类型。JAXB可以采取以下两种方式之一:
  • 不允许覆盖属性,这将非常限制。
  • 为被覆盖的属性生成一个额外的映射。在下面的模式中,child2类型扩展了parent。这意味着它获得了parent类型的所有元素以及自己的元素。
  <xs:complexType name="child2">
    <xs:complexContent>
      <xs:extension base="parent">
        <xs:sequence>
          <xs:element name="child1-list" minOccurs="0">
            <xs:complexType>
              <xs:sequence>
                <xs:element name="child-list-element" type="extendedElement2" minOccurs="0" maxOccurs="unbounded"/>
              </xs:sequence>
            </xs:complexType>
          </xs:element>
        </xs:sequence>
      </xs:extension>
    </xs:complexContent>

如何修复它

您可以在Parent类的list属性上放置@XmlTransient,但我建议注释Parent类并使用@XmlTransient

import java.util.List;
import javax.xml.bind.annotation.XmlTransient;

@XmlTransient
public abstract class Parent<T> {
    protected List<T> list;

    public abstract List<T> getList();
    public abstract void setList(List<T> list);

}

这将把它作为映射类移除,与Child2对应的复杂类型将变为:

  <xs:complexType name="child2">
    <xs:sequence>
      <xs:element name="child1-list" minOccurs="0">
        <xs:complexType>
          <xs:sequence>
            <xs:element name="child-list-element" type="extendedElement2" minOccurs="0" maxOccurs="unbounded"/>
          </xs:sequence>
        </xs:complexType>
      </xs:element>
    </xs:sequence>
  </xs:complexType>

但是如果你正在设计一个公共 API 呢?有没有一种方法提供一组默认的注释,并使它们可覆盖?我得到的印象是,根本没有办法做到这一点,我是正确的吗?请参阅:http://stackoverflow.com/questions/38348083/jaxb-override-xmlelement-type-of-list - bvdb

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接