2011-03-22 47 views
4

在我寫一個REST服務器通用的,我有一個包單品數的集合類從我的服務返回:做一個集合的javax.xml.bind

@XmlAccessorType(XmlAccessType.NONE) 
@XmlRootElement(name = "person_collection") 
public final class PersonCollection { 
    @XmlElement(name = "person") 
    protected final List<Person> collection = new ArrayList<Person>(); 

    public List<Person> getCollection() { 
     return collection; 
    } 
} 

我想重構這些使用泛型這樣的樣板代碼可以在超類中實現:

public abstract class AbstractCollection<T> { 
    protected final List<T> collection = new ArrayList<T>(); 

    public List<T> getCollection() { 
     return collection; 
    } 
} 

@XmlAccessorType(XmlAccessType.NONE) 
@XmlRootElement(name = "person_collection") 
public final class PersonCollection extends AbstractCollection<Person> {} 

如何設置在超集合@XmlElement註解?我正在考慮一些涉及@XmlJavaTypeAdapter和反思的內容,但希望更簡單些。如何創建JAXBContext?順便說一下,我正在爲JAX-RS前端使用RestEasy 1.2.1 GA。

UPDATE(安德魯白色):這裏是代碼演示獲取Class對象類型參數(一個或多個):

import java.lang.reflect.ParameterizedType; 
import java.lang.reflect.Type; 
import java.lang.reflect.TypeVariable; 
import java.util.ArrayList; 
import java.util.List; 

public class TestReflection 
     extends AbstractCollection<String> { 
    public static void main(final String[] args) { 
     final TestReflection testReflection = new TestReflection(); 

     final Class<?> cls = testReflection.getClass(); 
     final Type[] types = ((ParameterizedType) cls.getGenericSuperclass()).getActualTypeArguments(); 
     for (final Type t : types) { 
      final Class<?> typeVariable = (Class<?>) t; 
      System.out.println(typeVariable.getCanonicalName()); 
     } 
    } 
} 

class AbstractCollection<T> { 
    protected List<T> collection = new ArrayList<T>(); 
} 

這裏是輸出:java.lang.String

+0

您不必在'@ XmlElement'上指定'name'屬性,因此您可以將'@ XmlElement'添加到'AbstractCollection.collection'中,並讓JAXB推斷出元素名稱。 – skaffman 2011-03-23 11:14:33

+0

@skaffman:它不工作。我得到了一個'javax.xml.bind.JAXBException:class com.example.Person,但是它的任何超類都不知道這個上下文嗎? – Ralph 2011-03-23 12:19:33

+0

那麼這是你創建JAXB上下文的錯誤。將其添加到您的問題中,我將發佈答案。 – skaffman 2011-03-23 12:38:44

回答

1

思考問題

以下是反射測試需要進行的工作。我相信類型擦除是什麼阻止這種情況的發生:

import java.lang.reflect.Method; 
import java.util.ArrayList; 
import java.util.List; 

public class TestReflection extends AbstractCollection<String> { 

    private List<Integer> childCollection = new ArrayList<Integer>(); 


    public List<Integer> getChildCollection() { 
     return childCollection; 
    } 

    public static void main(final String[] args) throws Exception { 
     final TestReflection testReflection = new TestReflection(); 

     final Class<?> cls = testReflection.getClass(); 
     Method method1 = cls.getMethod("getChildCollection", new Class[] {}); 
     System.out.println(method1.getGenericReturnType()); 

     Method method2 = cls.getMethod("getCollection", new Class[] {}); 
     System.out.println(method2.getGenericReturnType()); 
    } 

} 

上面的代碼將輸出什麼如下所示。這是因爲「getCollection」方法位於AbstractCollection而不是TestReflection的上下文中。這是爲了確保Java二進制文件的向後兼容性:

java.util.List<java.lang.Integer> 
java.util.List<T> 

另類視角

如果集合中的項目將與@XmlRootElement進行註釋,那麼你可以達到你想要什麼做以下幾點:

import java.util.ArrayList; 
import java.util.List; 
import javax.xml.bind.annotation.XmlAnyElement; 

public abstract class AbstractCollection<T> { 

    protected List<T> collection = new ArrayList<T>(); 

    @XmlAnyElement(lax=true) 
    public List<T> getCollection() { 
     return collection; 
    } 

} 

並假設人看起來像這樣:

import javax.xml.bind.annotation.XmlRootElement; 

@XmlRootElement 
public class Person { 

} 

那麼下面的演示代碼:

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(PersonCollection.class, Person.class); 

     PersonCollection pc = new PersonCollection(); 
     pc.getCollection().add(new Person()); 
     pc.getCollection().add(new Person()); 

     Marshaller marshaller = jc.createMarshaller(); 
     marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); 
     marshaller.marshal(pc, System.out); 
    } 

} 

會產生:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<person_collection> 
    <person/> 
    <person/> 
</person_collection> 

欲瞭解更多信息,請參閱:

+0

但是,在這種情況下,我們不能只從子類('')讀取泛型?我無法在JAXB上找到不涉及XML模式的良好教程。我手工編寫我的類並需要對它們進行註釋,以便它們正確編組/解組。如果我不重構抽象超類,我的工作效果很好,但我不喜歡產生的樣板代碼的數量。 – Ralph 2011-03-24 13:19:02

+0

@Ralph - 訣竅是知道從子類可以應用到列表(我希望有一種方法)。我已經爲我的答案添加了一個替代方法,可能適合您。我的博客是從課程開始使用JAXB的一個很好的例子:http://bdoughan.blogspot.com/ – 2011-03-24 13:23:07

+0

您的編輯看起來很正確。我將不得不使用它。我會看看你的博客。 – Ralph 2011-03-24 13:23:30

0

認爲由於類型擦除,你所要求的是不可能的。任何通用解決方案都會失去解組所需容器的「類型」。

+0

我相信我可以使用反射(如果需要)獲取類型信息。 java.lang.reflect.Field.getGenericType()方法返回一個Type對象(可能是TypeVariable的實例),它可以用來檢索集合的實際類型。在最糟糕的情況下,我可以讓每個子類構造函數將其「子類型」的一個'Class '參數傳遞給'AbstractCollection'。 – Ralph 2011-03-22 13:00:09

+0

我希望你是對的,但我認爲那裏有一個限制;老實說,我不記得反射和泛型的注意事項,只有一些存在。 – 2011-03-22 13:05:41

+0

查看我的問題的更新。 – Ralph 2011-03-22 13:57:10

相關問題