Настройка обработки ошибок процесса демаршаллизации JAXB - PullRequest
5 голосов
/ 04 мая 2010

Предполагается, что у меня есть схема, которая описывает класс корневого элемента Root, который содержит List<Entry>, где класс Entry имеет обязательное имя поля.

Вот как это выглядит в коде:

@XmlRootElement 
class Root{
  @XmlElement(name="entry")
  public List<Entry> entries = Lists.newArrayList();
}

@XmlRootElement 
class Entry{
  @XmlElement(name="name",required=true)
  public String name;
}

Если я предоставлю следующий XML для демаршаллинга:

<root>
  <entry>
    <name>ekeren</name>
  </entry>
  <entry>
  </entry>
</root>

У меня проблема, потому что вторая запись не содержит имени. Таким образом, unmarshall производит null.

Есть ли способ настроить JAXB для отмены вызова Root объекта, который будет содержать только "хорошую" запись?

1 Ответ

5 голосов
/ 04 мая 2010

Вы можете добавить магический метод afterUnmarshal , чтобы позаботиться о пустых записях:

@XmlRootElement 
class Root{
  @XmlElement(name="entry")
  public List<Entry> entries = Lists.newArrayList();

  void afterUnmarshal(final Unmarshaller unmarshaller, final Object parent) {
    Iterator<Entry> iter = entries.iterator();
    while (iter.hasNext()) {
      if (iter.next().name == null) iter.remove();
    }
  }
}

EDIT:

Не уверен, что это лучше подходит для вас, но, возможно, это поможет. Вы также можете использовать Pacher, например если не все объекты, которые вам нужно исправить / проверить, доступны в afterUnmarshal (..)

Запускается UnmarshallingContext после того, как весь анализ выполнен. В основном используется для разрешения переадресации IDREF, но может выполнять любые действия. (Javadoc)

Вот пример:

@XmlRootElement 
class Entry{
  @XmlElement(name="name",required=true)
  public String name;

  private boolean isValidEntry() {
    return name != null;
  }

  void afterUnmarshal(final Unmarshaller unmarshaller, final Object parent) {
    if (!isValidEntry()) {
      // entry not yet added to parent - use a patcher
      UnmarshallingContext.getInstance().addPatcher(new Patcher() {
        public void run() throws SAXException {
          ((Root)parent).removeEntry(this);
        }
      });
    }
  }
}

Хотя я бы не стал злоупотреблять этим, не только потому, что это API только для Sun.

Но если вы действительно ищете что-то настраиваемое, которое не является частью кода самих маршаллированных объектов. Лучше всего смотреть на что-то после того, как разобраться. Интересно, не подойдет ли вам Bean Validation (JSR 303) , например, используя Hibernate Validator (не пугайтесь имени, вам не нужен Hibernate ORM, чтобы использовать его). Я не использовал его сам, но использование (нового) стандарта для проверки звучит разумно, не так ли?

...