Why my ArrayList is not marshalled with JAXB?

2019-02-04 12:04发布

问题:

Here is the use case:

@XmlRootElement
public class Book {
  public String title;
  public Book(String t) {
    this.title = t;
  }
}
@XmlRootElement
@XmlSeeAlso({Book.class})
public class Books extends ArrayList<Book> {
  public Books() {
    this.add(new Book("The Sign of the Four"));
  }
}

Then, I'm doing:

JAXBContext ctx = JAXBContext.newInstance(Books.class);
Marshaller msh = ctx.createMarshaller();
msh.marshal(new Books(), System.out);

This is what I see:

<?xml version="1.0"?>
<books/>

Where are my books? :)

回答1:

The elements to be marshalled must be public, or have the XMLElement anotation. The ArrayList class and your class Books do not match any of these rules. You have to define a method to offer the Book values, and anotate it.

On your code, changing only your Books class adding a "self getter" method:

@XmlRootElement
@XmlSeeAlso({Book.class})
public class Books extends ArrayList<Book> {
  public Books() {
    this.add(new Book("The Sign of the Four"));
  }

  @XmlElement(name = "book")
  public List<Book> getBooks() {
    return this;
  }
}

when you run your marshalling code you'll get:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<books><book><title>The Sign of the Four</title></book></books>

(I added a line break for clarity's shake)



回答2:

I don't think you can easily marshall a List as is. Consider using another class to wrap the list in. The following works:

@XmlType
class Book {
    public String title;

    public Book() {
    }

    public Book(String t) {
        this.title = t;
    }
}

@XmlType
class Books extends ArrayList<Book> {
    public Books() {
        this.add(new Book("The Sign of the Four"));
    }
}

@XmlRootElement(name = "books")
class Wrapper {
    public Books book = new Books();
}

Used like the following:

JAXBContext ctx = JAXBContext.newInstance(Wrapper.class);
Marshaller msh = ctx.createMarshaller();
msh.marshal(new Wrapper(), System.out);

it produces this result:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<books><book><title>The Sign of the Four</title></book></books>


回答3:

As @Blaise and @musiKk have pointed out, it would be better to simply have a List of Book in Books, and allow Books to be the true root element. I would not consider the extending of ArrayList an acceptable procedure in my own code.



标签: java xml jaxb