在javax.xml.bind中创建一个通用集合 [英] Make a collection generic in javax.xml.bind

查看:90
本文介绍了在javax.xml.bind中创建一个通用集合的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

In a REST server that I've written, I have several collection classes that wrap single items to be returned from my services:

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

我想重构这些以使用泛型所以样板代码可以在超类中实现:

I would like to refactor these to use generics so the the boilerplate code can be implemented in a superclass:

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。

How do I set the @XmlElement annotation on the superclass collection? I am thinking of something involving a @XmlJavaTypeAdapter and reflection, but was hoping for something simpler. How do I create the JAXBContext? BTW, I am using RestEasy 1.2.1 GA for the JAX-RS front-end.

UPDATE (对于Andrew White):这是演示获取类型参数的 Class 对象的代码:

UPDATE (for Andrew White): Here is code that demonstrates getting the Class object for the type parameter(s):

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

推荐答案

反思问题

以下是需要进行的反射测试。我相信类型擦除是阻止这种情况发生的原因:

The following is the reflection test that needs to be made work. I believe type erasure is what is preventing this from happening:

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二进制文件的向后兼容性:

The above code will output what is shown below. This is because the "getCollection" method is in the context of AbstractCollection and not TestReflection. This is to ensure backwards compatibility of the Java binaries:

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






替代方法

如果集合中的项目将使用@XmlRootElement注释,那么您可以通过以下方式实现您想要的操作:

If the items in the collection will be annotated with @XmlRootElement, then you could achieve what you want to do with the following:

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

}

假设Person看起来如下:

And assuming Person looks like the following:

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>

有关详细信息,请参阅:

For more information see:

  • http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html

这篇关于在javax.xml.bind中创建一个通用集合的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆