Преобразование пустого элемента в ноль при отмене сортировки с помощью JAXB - PullRequest
10 голосов
/ 15 ноября 2010

Класс определяется с помощью следующей аннотации JAXB:

class Course {
@XmlElement (name = "book")
List<Book> requiredBooks = new ArrayList<Book>();

При отмене сортировки XML-документа, содержащего это

<course>
  ...
  <book/>
</course>

, я получаю книгу, добавленную в списоксо всеми его атрибутами, установленными в нуль.Я не контролирую ввод XML.Как я могу предотвратить добавление этой пустой книги?Я попытался перехватить в методах set .. () или add .. (), но оказалось, что JAXB обходит сеттеры при работе с коллекциями.Есть предложения?

Ответы [ 6 ]

5 голосов
/ 16 ноября 2010

Вот решение, которое работает . И снова элегантность осталась позади.

Существует два обратных вызова, определенных JAXB: beforeUnmarshal и afterUnmarshal. Реализовав afterUnmarshal для очистки списка, я смог достичь желаемого результата.

  class Course
  {
    @XmlElement (name = "book")
    List<Book> requiredBooks = new ArrayList<Book>();  
    ...
    void afterUnmarshal(Unmarshaller aUnmarshaller, Object aParent)
    {
        if (requiredBooks != null)
        {
            Iterator<Book> iterator = requiredBooks.iterator();
            while (iterator.hasNext())
            {
                Book book = iterator.next();
                if (StringUtils.isEmpty(book.getTitle()))
                {
                    // a book without title is considered invalid
                    iterator.remove();
                }
            }
        }
    }
  }

Хотя это работает, самой большой проблемой является отсутствие интерфейса для реализации afterUnmarshal. JAXB искал его с помощью рефлексии, но я думаю, что было бы удобно (и уменьшило бы отладку / обслуживание), если бы JAXB просто предоставлял интерфейсы и / или реализовывал реализации. Как это так, что, если подпись afterUnmarshal изменится в будущем? Этот код просто загадочным образом перестанет работать, как и предполагалось.

4 голосов
/ 16 ноября 2010

В EclipseLink JAXB (MOXy) у нас есть концепция нулевой политики.Эта нулевая политика дает вам некоторую гибкость при представлении нулевого значения.

Вы можете изменить свой класс так, чтобы он выглядел следующим образом:

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>();
}

Это сообщает MOXy JAXB, что для этого свойства вы хотитеобрабатывать пустые элементы как ноль для этого свойства.

Для этого XML:

<course>
    <book/>
    <book>
        <title>Hello World</title>
    </book>
    <book/>
</course>

Свойство requiredBooks будет отменено как: ноль, aBook, нуль.

В настоящее время существует ошибка, которая мешает этому работать, к которой мы сейчас обращаемся.Вы можете отслеживать прогресс в этом вопросе здесь:

2 голосов
/ 15 ноября 2010

Ну, Я нашел один способ сделать это, хотя я не нахожу его супер элегантным.

Редактировать: На самом деле, решение ниже не работает должным образом. Фактически это не приводит к добавлению записей в список, независимо от того, являются ли они пустым элементом или полностью сформированы с данными.

Возможно, я сделал это неправильно, поэтому любые комментарии приветствуются.

Я создал адаптер для обработки преобразования и сообщил JAXB с помощью аннотации:

class Course {
@XmlElement (name = "book")
@XmlJavaTypeAdapter(BookListAdapter.class)
List<Book> requiredBooks = new ArrayList<Book>();

и затем определил мой адаптер:

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;
    }
}

Он работает так, как я хочу, но, как я уже говорил, я не уверен в его элегантности.
Редактировать: Как описано выше, это не работает, но, вероятно, из-за какой-то ошибки с моей стороны.

1 голос
/ 11 мая 2012

Я сделал похожий глин:

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);
}

Но я обнаружил, что это так ужасно, что я просто переключился на Gson ;)

1 голос
/ 15 ноября 2010

Попробуйте это,

class Course {
@XmlElement (name="book", required=false)
List<Book> requiredBooks = new ArrayList<Book>();
0 голосов
/ 30 октября 2013

У меня была похожая проблема - мне нужно обработать ArrayList, содержащий интерфейсы. Я только что создал адаптер для интерфейса (MyInterfaceAdapter) и аннотировал список:

@XmlElementWrapper(name="myInterface")
@XmlJavaTypeAdapter(value=MyInterfaceAdapter.class)
List<MyInterface> list = new ArryList<MyInterface>;

Мой адаптер выглядит так:

public class MyInterfaceAdapter extends XmlAdapter<MyType, MyInterface> {

@Override
public Sensor unmarshal(MyType v) throws Exception {
    return (MyInterface) v;
}

@Override
public AbstractSensor marshal(MyInterface v) throws Exception {     
        if(v == null) //In the case of empty list
        {
         return null;
        } else
        { .....return new ... }
    }
}

После демаршаллинга у меня есть инициализированный ArrayList (даже пустой).

Я думаю, что в вышеупомянутой задаче можно добавить дополнительные условия и вернуть пустое значение в случае пустой книги С другой стороны, я также не люблю возвращать ноль.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...