在javax.xml.bind中使集合成为泛型集合

在javax.xml.bind中使集合成为泛型集合,java,jaxb,jax-rs,resteasy,Java,Jaxb,Jax Rs,Resteasy,在我编写的REST服务器中,我有几个集合类,它们包装要从我的服务返回的单个项: @XmlAccessorType(XmlAccessType.NONE) @XmlRootElement(name = "person_collection") public final class PersonCollection { @XmlElement(name = "person") protected final List<Person> collection = new Ar

在我编写的REST服务器中,我有几个集合类,它们包装要从我的服务返回的单个项:

@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;
    }
}

以下是输出:
java.lang.String

我认为由于类型擦除,您所要求的是不可能的。任何通用解决方案都会丢失解组所需的容器的“类型”

反思问题

下面是需要进行的反射测试。我认为类型擦除是防止这种情况发生的原因:

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());
   }

}
然后是以下演示代码:

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>

有关更多信息,请参阅:


我相信我可以使用反射(如有必要)获得类型信息。方法
java.lang.reflect.Field.getGenericType()
返回一个
Type
对象(可能是
TypeVariable
的实例),该对象可用于检索集合的实际类型。在最坏的情况下,我可以让每个子类构造函数将其“child”类型的单个
Class
参数传递给
AbstractCollection
;老实说,我已经记不起反射和泛型的注意事项了,只是有些存在。你不必在
@xmlement
上指定
@xmlement
属性,所以你只需将
@xmlement
添加到
AbstractCollection.collection
,让JAXB推断出元素名。@skaffman:它不起作用。我得到了一个
javax.xml.bind.JAXBException:class com.example.Person,它的任何超类都不为这个上下文所知。把这个加在你的问题上,我会发布一个答案。@skaffman:补充。请参见上文:-)。+1个很好的问题-目前正在使用EclipseLink JAXB(MOXy)调试此问题。但是,在这种情况下,我们不能从子类(
)中读取泛型类型吗?我找不到一个不涉及XML模式的关于JAXB的好教程。我手工编写了我的类,需要对它们进行注释,以便它们能够正确地封送/解封。如果我不重构成一个抽象的超类,我会让它工作得很好,但我不喜欢生成大量的样板代码。@Ralph-诀窍是知道从子类可以应用到列表(我希望有一种方法)。我在我的回答中添加了一种可能对您有用的替代方法。我的博客是从类开始使用JAXB的一个很好的例子:您的编辑看起来很正确。我得玩它。我来看看你的博客。@Ralph-你可能会发现以下文章很有用:
java.util.List<java.lang.Integer>
java.util.List<T>
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>