Search code examples
javajaxb2

JAXB and enum implementing interface


I am new with JAXB (and with Stackoverflow too!) and I ran into problems when trying to marshal and unmarshal an object which contains a list of enums implementing an interface. I had a look here and I tried a similar example:

public class testXML {
    private static interface Animal {
        public String getName();
    }

    @XmlRootElement
    private static class Lion implements Animal {
        @XmlElement
        private String name;
        public Lion() { name = "Lion"; }
        @Override public String getName() {
            return name;
        }
    }

    @XmlRootElement
    private static class Dog implements Animal {
        @XmlElement
        private String name;
        public Dog() { name = "Dog"; }
        @Override public String getName() {
            return name;
        }
    }

    @XmlRootElement
    private static class Zoo {
      @XmlElementRefs({
          @XmlElementRef(name = "lion", type = Lion.class, required = true),
          @XmlElementRef(name = "dog", type = Dog.class, required = true)
      })
      public List<Animal> animals;
      public Zoo(Animal ... animals) {
          this.animals = Arrays.asList(animals);
      }
      public Zoo() {
          animals = null;
      }
      public Animal getAnimal(int i) {
          return animals.get(i);
      }
    }

    public static void main(String[] args) throws JAXBException {
        File file = new File("testXML.xml");
        JAXBContext context = JAXBContext.newInstance(
                Zoo.class,
                Lion.class,
                Dog.class);
        //SerializableParameter<ChannelParamEnum> result = new SerializableParameter(ChannelParamEnum.PARAM_CH_FGAIN, 1.0);
        Zoo result = new Zoo(new Lion(), new Dog());
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(result, file);

        Zoo unmar = (Zoo)context.createUnmarshaller().unmarshal(file);
        Animal anim = unmar.getAnimal(0);
        System.out.println(anim);
    }
}

This worked without problems. I then tried to switch Lion and Dog classes into enums and tried the following:

public class testXML {
    private static interface Animal {
        public String getName();
    }

    @XmlRootElement
    private static enum Lion implements Animal {
        SIMBA("Simba"),
        MUFASA("Mufasa"),
        SCAR("Scar");

        private String name;
        Lion(String name) { this.name = name; }
        @Override public String getName() {
            return name;
        }
    }

    @XmlRootElement
    private static enum Dog implements Animal {
        PONGO("Pongo"),
        PEGGY("Peggy");

        private String name;
        Dog(String name) { this.name = name; }
        @Override public String getName() {
            return name;
        }
    }

    @XmlRootElement
    private static class Zoo {
      @XmlElementRefs({
          @XmlElementRef(name = "lion", type = Lion.class),
          @XmlElementRef(name = "dog", type = Dog.class)
      })
      public List<Animal> animals;
      public Zoo(Animal ... animals) {
          this.animals = Arrays.asList(animals);
      }
      public Zoo() {
          animals = null;
      }
      public Animal getAnimal(int i) {
          return animals.get(i);
      }
    }

    public static void main(String[] args) throws JAXBException {
        File file = new File("testXML.xml");
        JAXBContext context = JAXBContext.newInstance(
                Lion.class,
                Dog.class,
                Zoo.class);
        Zoo result = new Zoo(Lion.SIMBA, Lion.SCAR, Dog.PONGO);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.marshal(result, file);

        Zoo unmar = (Zoo)context.createUnmarshaller().unmarshal(file);
        Animal anim = unmar.getAnimal(0);
        System.out.println(anim);
    }
}

This code fails at runtime in JAXBContext.newInstance with

Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Invalid @XmlElementRef : Type "package.testXML$Lion" or any of its subclasses are not known to this context.

Obviously this is not my use-case, and I have to use enums instead of classes. I looked around a lot, but I didn't find an answer, so any help is greatly appreciated.

Thank you!


Solution

  • Finally I found the solution. It was enough to change

      @XmlElementRefs({
          @XmlElementRef(name = "lion", type = Lion.class),
          @XmlElementRef(name = "dog", type = Dog.class)
      })
    

    with

      @XmlElements({
          @XmlElement(name="lion", type=Lion.class),
          @XmlElement(name="dog", type=Dog.class)
      })
    

    Anyway, I still feel that I'm missing a lot as regards JAXB utilization.

    I hope this help!