JAXB Annotations - Mapping interfaces and @XmlElementWrapper

18,202

Solution 1

This is a bug that was fixed in JAXB 2.1.13. Update your libraries or use JDK 1.7 or later and the problem will be solved.

Solution 2

Should use @XmlElementRefs({ @XmlElementRef(type=Dog.class), @XmlElementRef(type=Cat.class)}) private List animals;

or use @XmlAnyElement(lax = true) only, and add Dog.class, Cat.class to JaxbContext

Share:
18,202
codefinger
Author by

codefinger

JVM Platform Owner at Heroku

Updated on June 05, 2022

Comments

  • codefinger
    codefinger almost 2 years

    I am having trouble with JAXB annotations for a field that is a list whose generified type is an interface. When I have it declared such as:

    @XmlAnyElement
    private List<Animal> animals;
    

    Every thing works correctly. But when I add a wrapper element, such as:

    @XmlElementWrapper
    @XmlAnyElement
    private List<Animal> animals;
    

    I find that the Java object marshals correctly, but when I unmarshal the document created by marshaling, my list is empty. I have posted below the code to demonstrate this problem.

    Am I doing something wrong, or is this a bug? I have tried it with version 2.1.12 and 2.2-ea with the same result.

    I am working through the example for mapping interfaces with annotations located here: https://jaxb.dev.java.net/guide/Mapping_interfaces.html

    @XmlRootElement
    class Zoo {
    
      @XmlElementWrapper
      @XmlAnyElement(lax = true)
      private List<Animal> animals;
    
      public static void main(String[] args) throws Exception {
        Zoo zoo = new Zoo();
        zoo.animals = new ArrayList<Animal>();
        zoo.animals.add(new Dog());
        zoo.animals.add(new Cat());
    
        JAXBContext jc = JAXBContext.newInstance(Zoo.class, Dog.class, Cat.class);
        Marshaller marshaller = jc.createMarshaller();
    
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        marshaller.marshal(zoo, os);
    
        System.out.println(os.toString());
    
        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Zoo unmarshalledZoo = (Zoo) unmarshaller.unmarshal(new ByteArrayInputStream(os.toByteArray()));
    
        if (unmarshalledZoo.animals == null) {
          System.out.println("animals was null");
        } else if (unmarshalledZoo.animals.size() == 2) {
          System.out.println("it worked");
        } else {
          System.out.println("failed!");
        }
      }
    
      public interface Animal {}
    
      @XmlRootElement
      public static class Dog implements Animal {}
    
      @XmlRootElement
      public static class Cat implements Animal {}
    }