自定义JAXB unmarshall进程的错误处理

eke*_*ren 5 java xml jaxb unmarshalling

假设我有一个描述根元素类架构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;
}
Run Code Online (Sandbox Code Playgroud)

如果我提供以下XML用于解组:

<root>
  <entry>
    <name>ekeren</name>
  </entry>
  <entry>
  </entry>
</root>
Run Code Online (Sandbox Code Playgroud)

我有一个问题,因为第二个条目不包含名称.因此,unmarshall产生null.

有没有办法自定义JAXB来解组一个Root只包含"好"条目的对象?

sfu*_*ger 5

您可以添加神奇的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();
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

编辑:

不确定这是否更适合你,但也许它有所帮助.您也可以使用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);
        }
      });
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

我不会过分滥用它,不仅因为它是Sun-only API.

但是,如果您真的在寻找可配置的东西,而这些东西不是编组对象本身的代码的一部分.解组后最好看一些东西.我想知道Bean Validation(JSR 303)是否适合你,例如使用Hibernate Validator(不要被名字吓倒,你不需要Hibernate ORM来使用它).我自己没有使用它,但使用(新)标准进行验证听起来合理,不是吗?