2011-03-22 21 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

相关问题