Marshalling a List of objects implementing a common interface, with JaxB

后端 未结 2 878
余生分开走
余生分开走 2020-12-01 01:06

I am trying to marshall a list of objects implementing a common interface. There are 3 classes and 1 interface involved:

Community class (has one me

相关标签:
2条回答
  • 2020-12-01 01:20

    OK, if you're prepared to change Person from an interface into an abstract base class, then you're golden. Here's the code:

    public class Main {
    
    
      public static void main(String[] args) throws Exception {
    
        Community community = new Community();
    
        JAXBContext context = JAXBContext.newInstance(Community.class);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(community, System.out);
    
      }
    }
    
    @XmlRootElement(name = "community")
    @XmlSeeAlso({Person.class})
    public class Community {
    
     private List<Person> people;
    
     @XmlElementWrapper(name="people")
     @XmlElementRef()
     public List<Person> getPeople() {
      return people;
     }
    
     public Community() {
      people = new ArrayList<Person>();
      people.add(new Girl());
      people.add(new Boy());
      people.add(new Girl());
      people.add(new Boy());
     }
    }
    
    @XmlRootElement(name="boy")
    public class Boy extends Person {
    
     public String getName() {
      return "John";
     }
    }
    
    @XmlRootElement(name="girl")
    public class Girl extends Person {
    
     public String getName() {
      return "Jane";
     }
    }
    
    @XmlRootElement(name = "person")
    @XmlSeeAlso({Girl.class,Boy.class})
    public abstract class Person {
    
      @XmlElement(name="name")
     public abstract String getName();
    }
    

    The main trick was the use of @XmlElementRef in the List of Community. This identifies the type of the class through it's @XmlRootElement. You may also be interested in the @XmlSeeAlso which helps to organise context declarations.

    And the output is

    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <community>
        <people>
            <girl>
                <name>Jane</name>
            </girl>
            <boy>
                <name>John</name>
            </boy>
            <girl>
                <name>Jane</name>
            </girl>
            <boy>
                <name>John</name>
            </boy>
        </people>
    </community>
    
    0 讨论(0)
  • 2020-12-01 01:28

    For this scenario I would recommend the use of @XmlElements. @XmlElements is used to represent the XML schema concept of choice:

    • http://bdoughan.blogspot.com/2010/10/jaxb-and-xsd-choice-xmlelements.html

    Here is how it would look for your example:

    @XmlElements({ 
        @XmlElement(name="girl", type=Girl.class),
        @XmlElement(name="boy", type=Boy.class)
    })
    @XmlElementWrapper
    public List<Person> getPeople() {
        return people;
    }
    

    @XmlElementRef corresponds to the concept of substitution groups in XML schema. This is why the previous answer requires Person to be changed from an interface to a class.

    • http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-using-substitution.html
    0 讨论(0)
提交回复
热议问题