In javax xml. Create a general collection in bind
In the rest server I write, I have several collection classes that contain a single item returned from my service:
@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 want to refactor these to use generics, so the boilerplate code can be implemented in superclasses:
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> {}
How do I set the @ xmlelement annotation on a superclass collection? I'm thinking about something involving @ xmljavatypeadapter and reflection, but I want something simpler How do I create a jaxbcontext? By the way, I'm using resteasy 1.2 1 GA as jax-rs front end
Update (for Andrew white): This is the code that demonstrates the class object that gets the type parameter:
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>(); }
This is the output: Java lang.String.
Solution
Reflection problem
The following is the reflection test to be performed I believe type erasure is the reason to prevent 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()); } }
The above code will output the following This is because the "getcollection" method is in the context of abstractcollection, not testreflection This is to ensure backward compatibility of Java binaries:
java.util.List<java.lang.Integer> java.util.List<T>
Alternative methods
If the items in the collection will use the @ xmlrootelement annotation, you can do what you want 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; } }
Suppose person looks like this:
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Person { }
Then the following demo code:
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); } }
Will produce:
<?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