2012-12-18 18 views
10
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"; 
} 

Come ho mostrato nell'esempio quando ho rimuovo il @XmlTransient dal metodo Parent classe getList(), a seguito di xml è marshalling:In che modo Inheritance e JAXB funzionano insieme?

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

Ma quando aggiungo il @XmlTransient annotazioni, come in Nell'esempio l'xml è serializzato con la sola lista ONE come richiesto.

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

Quindi, per favore qualcuno mi può spiegare perché si è tenuto a dare @XmlTransient in Parent metodo di classe getter? In che modo l'ereditarietà e il JAXB interagiscono tra loro in questi casi?

risposta

6

PERCHE suo accadere

Un JAXB (JSR-222) attuazione mappare ogni oggetto di dominio che è a conoscenza di un tipo complesso. Ciò significa che ritiene che il seguente tipo XML esiste per la classe Parent (quando list non è @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> 

Ora Child2 ha anche un tipo complesso. Ci sono due cose che JAXB avrebbe potuto fare:

  • Non consentire l'override delle proprietà, il che sarebbe piuttosto limitante.
  • Genera un'ulteriore mappatura per la proprietà sostituita. Nello schema sotto il tipo child2 si estende parent. Ciò significa che ottiene tutti gli elementi dal tipo parent più il proprio.
<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> 

come risolvere il problema

si potrebbe mettere @XmlTransient sulla proprietà list nella classe Parent, ma invece mi sento di raccomandare l'annotazione della classe Parent con @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); 

} 

Questo eliminerà come una classe mappata e il tipo complesso che corrisponde al Child2 diventerà:

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

Ma cosa succede se si sta progettando un'API pubblica? C'è un modo per fornire un set predefinito di annotazioni e renderle superabili? Ho l'impressione che non ci sia modo di farlo, ho ragione? vedere: http://stackoverflow.com/questions/38348083/jaxb-override-xmlelement-type-of-list – bvdb

Problemi correlati