2011-10-21 9 views
8

Đây là kịch bản của tôi. Tôi có một lớp generic:Trường trùng lặp trong XML được tạo bằng cách sử dụng JAXB

public class Tuple<T> extends ArrayList<T> { 
    //... 
    public Tuple(T ...members) { 
    this(Arrays.asList(members)); 
    } 

    @XmlElementWrapper(name = "tuple") 
    @XmlElement(name = "value") 
    public List<T> getList() { 
    return this; 
    } 
} 

Và một lớp trẻ:

public class StringTuple extends Tuple<String> { 
    public StringTuple(String ...members) { 
    super(members); 
    } 

    //explanation of why overriding this method soon ... 
    @XmlElementWrapper(name = "tuple") 
    @XmlElement(name = "value") 
    @Override 
    public List<String> getList() { 
    return this; 
    } 
} 

Những lớp được tham chiếu ở đây:

@XmlRootElement(namespace = "iv4e.xml.jaxb.model") 
public class Relation { 
    private Tuple<StringTuple> relationVars; 
    //... 
    @XmlElementWrapper(name = "allRelationVars") 
    @XmlElement(name = "relationVarsList") 
    public Tuple<StringTuple> getRelationVars() { 
    return relationVars; 
    } 
} 

Sau đó, một đối tượng Relation được tạo ra với một cái gì đó như:

Relation rel = new Relation(); 
rel.setRelationVars(new Tuple<StringTuple>(
    new StringTuple("RelationshipVar1"), new StringTuple("RelationshipVar2"))); 

Sau khi đầm lầy đối tượng này, đầu ra Xml là như sau:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<ns2:relation xmlns:ns2="iv4e.xml.jaxb.model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=""> 

    <allRelationVars> 
    <relationVarsList> 
     <tuple> 
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar1</value> 
     </tuple> 
     <tuple> 
      <value>RelationshipVar1</value> 
     </tuple> 
    </relationVarsList> 
    <relationVarsList> 
     <tuple> 
      <value xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:string">RelationshipVar2</value> 
     </tuple> 
     <tuple> 
      <value>RelationshipVar2</value> 
     </tuple> 
    </relationVarsList> 
    </allRelationVars> 

</ns2:relation> 

Vì vậy, các yếu tố value được nhân đôi !.

Bây giờ, lý do StringTuple lớp đè List<T> getList() với List<String> getList() là tránh gây phiền nhiễu tạo ra xmlns:xs thuộc tính trong mỗi thành viên của danh sách (các value yếu tố trong tài liệu xml). Nhưng sau đó mọi thành viên của danh sách được hiển thị hai lần trong đầu ra. Rõ ràng, đó là bởi vì cả hai phương pháp cha mẹ ghi đè và phương pháp con được chú thích với @XmlElement. Vì vậy, câu hỏi chính của tôi là: có một cách để bỏ qua các phương pháp ghi đè được chú thích với @XmlElement trong Jaxb? (xem xét phương pháp ghi đè cũng được chú thích với @XmlElement)

Tôi tìm thấy một bài đăng cũ báo cáo vấn đề tương tự: http://old.nabble.com/@XmlElement-on-overridden-methods-td19101616.html, nhưng tôi chưa tìm thấy bất kỳ giải pháp nào. Cũng lưu ý rằng việc thêm chú thích @XmlTransient vào phương thức getList ở lớp cha (Tuple<T>) có thể giải quyết vấn đề này nhưng sẽ tạo ra các vấn đề khác, vì lớp cha không trừu tượng và chỉ được sử dụng một mình trong các ngữ cảnh khác.

Câu hỏi phụ một bên: có thể khai báo thuộc tính xmlns:xs ở nút gốc thay vì xuất hiện ở mọi nút khi cần thiết không? Tôi biết điều này có thể được thực hiện với các lớp học NamespacePrefixMapper, nhưng vì nó là một tiêu chuẩn, SUN nội bộ lớp học, tôi thay vì thích sử dụng một cách tiếp cận độc lập thực hiện hơn.

Cảm ơn trước vì đã có phản hồi!

+1

Trước khi tôi nhận được quá xa vào vấn đề này, làm đối tượng miền của bạn cần phải mở rộng 'ArrayList'? Tại sao 'Tuple' mở rộng' ArrayList' thay vì có thuộc tính của kiểu 'ArrayList'? –

+0

Xin chào Blaise !, Tôi đã chọn kế thừa từ ArrayList vì đối tượng Tuple của tôi thực ra là một ArrayList. Tuy nhiên, tôi có thể sống với nó có chứa một ArrayList thay vào đó, mặc dù sau đó tôi sẽ phải thực hiện một số phương pháp đại biểu. Dù sao, điều đó sẽ không giải quyết được vấn đề của tôi vì tôi vẫn sẽ có một lớp chung Tuple, và một StringTuple mở rộng Tuple . – Sergio

+0

Tôi đã thêm một câu trả lời với một cách tiếp cận có thể được sử dụng để loại bỏ khai báo 'xsi: type'. –

Trả lời

3

Bạn có thể sử dụng các phương pháp sau đây đánh dấu tài sản @XmlTransient trên phụ huynh và @XmlElement trên con:

Chánh

package forum7851052; 

import java.util.ArrayList; 
import java.util.List; 

import javax.xml.bind.annotation.XmlRootElement; 
import javax.xml.bind.annotation.XmlTransient; 

@XmlRootElement 
public class Parent<T> { 

    private List<T> item = new ArrayList<T>(); 

    @XmlTransient 
    public List<T> getItem() { 
     return item; 
    } 

    public void setItem(List<T> item) { 
     this.item = item; 
    } 

} 

IntegerChild

package forum7851052; 

import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class IntegerChild extends Parent<Integer> { 

    @Override 
    @XmlElement 
    public List<Integer> getItem() { 
     return super.getItem(); 
    } 

    @Override 
    public void setItem(List<Integer> item) { 
     super.setItem(item); 
    } 

} 

StringC Hild

package forum7851052; 

import java.util.List; 

import javax.xml.bind.annotation.XmlElement; 
import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class StringChild extends Parent<String> { 

    @Override 
    @XmlElement 
    public List<String> getItem() { 
     return super.getItem(); 
    } 

    @Override 
    public void setItem(List<String> item) { 
     super.setItem(item); 
    } 

} 

Demo

package forum7851052; 

import javax.xml.bind.JAXBContext; 
import javax.xml.bind.Marshaller; 

public class Demo { 

    public static void main(String[] args) throws Exception { 
     JAXBContext jc = JAXBContext.newInstance(Parent.class, IntegerChild.class, StringChild.class); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 

     IntegerChild integerChild = new IntegerChild(); 
     integerChild.getItem().add(1); 
     integerChild.getItem().add(2); 
     marshaller.marshal(integerChild, System.out); 

     StringChild stringChild = new StringChild(); 
     stringChild.getItem().add("A"); 
     stringChild.getItem().add("B"); 
     marshaller.marshal(stringChild, System.out); 
    } 

} 

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<integerChild> 
    <item>1</item> 
    <item>2</item> 
</integerChild> 
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<stringChild> 
    <item>A</item> 
    <item>B</item> 
</stringChild> 
+0

Điều gì sẽ xảy ra nếu Phụ huynh được sử dụng trong tuần tự hóa (làm cho trường tạm thời của phụ huynh không phải là một lựa chọn)? Đó là trường hợp hoàn toàn hợp lệ, nhưng JAXB có vẻ như đã nhập chú thích @Override. – stuchl4n3k

2

Điều này có thể khá cũ, nhưng kết quả đầu tiên của mình trong khi tìm kiếm "JAXB lặp lại các lĩnh vực"

Vượt qua cùng một vấn đề, điều này đã làm cho các trick cho tôi:

@XmlRootElement 
@XmlAccessorType(XmlAccessType.NONE) // <-- made the difference 
public abstract class ParentClass 
{ 
... 
} 


@XmlRootElement 
public class ChildClass extends ParentClass 
{ 
... 
}