【问题标题】:How do Inheritance and JAXB work together?继承和 JAXB 如何协同工作?
【发布时间】:2012-12-05 09:05:40
【问题描述】:
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";
}

正如我在示例中所展示的,当我从ParentgetList() 方法中删除 @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 会根据需要仅使用 ONE 列表进行序列化。

<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 如何相互关联?

【问题讨论】:

    标签: java jaxb xml-serialization


    【解决方案1】:

    为什么会发生

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

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

    如何解决

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

    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 怎么办?有没有办法提供一组默认注释,并使它们可覆盖?我的印象是没有办法做到这一点,对吗?见:stackoverflow.com/questions/38348083/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-02
    • 1970-01-01
    相关资源
    最近更新 更多