A class is defined with the following JAXB annotation:
class Course {
@XmlElement (name = "book")
List<Book> requiredBooks = new ArrayList<Book>();
When unmarshalling an XML document that contains this
<course>
...
<book/>
</course>
I end up with a Book added to the list, with all of its attributes set to null. I don't control the XML input. How can I prevent this empty book from being added? I tried intercepting in set..() or add..() methods, but turns out JAXB bypasses setters when dealing with collections. Any suggestions?
Well, I found one way to do it, although I don't find it super elegant.
Edit: Actually, the solution below doesn't work properly. It actually causes no entries to be added to the list, regardless of them being an empty element or fully formed with data.
Maybe I've done it wrong, so any comments are welcome.
I created an adapter to handle the conversion and informed JAXB using an annotation:
class Course {
@XmlElement (name = "book")
@XmlJavaTypeAdapter(BookListAdapter.class)
List<Book> requiredBooks = new ArrayList<Book>();
and then defined my adapter:
static class BookListAdapter extends XmlAdapter<Book[], List<Book>>
{
public Book[] marshal(List<Book> aBookList)
{
if (aBookList!= null)
{
return aBookList.toArray(new Book[aBookList.size()]);
}
return null;
}
public List<Book> unmarshal(Book[] aBookArray)
{
List<Book> bookList = new ArrayList<Book>();
if (aBookArray != null)
{
for (Book book : aBookArray)
{
if (StringUtils.isNotEmpty(book.getTitle()))
{
bookList.add(book);
}
}
}
return bookList;
}
}
It works as I want it to, but, as I said earlier, I'm not convinced of its elegance.
Edit: As described above, this doesn't work but probably due to some error on my part.
In EclipseLink JAXB (MOXy) we have the concept of a null policy. This null policy gives you some flexibility on how to represent null.
You could modify your class to look like the following:
import org.eclipse.persistence.oxm.annotations.XmlMarshalNullRepresentation;
import org.eclipse.persistence.oxm.annotations.XmlNullPolicy;
@XmlRootElement
class Course {
@XmlElement (name = "book")
@XmlNullPolicy(
nullRepresentationForXml = XmlMarshalNullRepresentation.EMPTY_NODE,
emptyNodeRepresentsNull=true)
List<Book> requiredBooks = new ArrayList<Book>();
}
This informs MOXy JAXB that for this property you wish to treat empty elements as null for this property.
For this XML:
<course>
<book/>
<book>
<title>Hello World</title>
</book>
<book/>
</course>
The requiredBooks property would unmarshal as: null, aBook, null.
There is currently a bug that is preventing this from working that we are addressing now. You can track the progress on this issue here:
Try this,
class Course {
@XmlElement (name="book", required=false)
List<Book> requiredBooks = new ArrayList<Book>();
I did a similar cludge:
public List<Photo> getPhotos() {
removeUninitializedPhotos();
return photos;
}
private void removeUninitializedPhotos() {
List<Photo> photosToRemove = new ArrayList<Photo>();
for (Photo photo : photos) {
if (photo.getId() == null) {
photosToRemove.add(photo);
}
}
photos.removeAll(photosToRemove);
}
But I found it so horrible that I just ended up switching to Gson ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With