使用JAXB解组时将空元素转换为null

时间:2010-11-15 03:09:36

标签: java jaxb

使用以下JAXB注释定义类:

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

解组包含此

的XML文档时
<course>
  ...
  <book/>
</course>

我最终将一本书添加到列表中,其所有属性都设置为null。我不控制XML输入。如何防止添加此空白书?我尝试拦截set ..()或添加..()方法,但是在处理集合时,JAXB绕过了setter。有什么建议吗?

6 个答案:

答案 0 :(得分:5)

这是 工作的解决方案。再次,优雅被遗忘。

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的签名将来会发生什么变化呢?这段代码只会神秘地停止工作。

答案 1 :(得分:4)

EclipseLink JAXB (MOXy)中,我们有一个空策略的概念。这个空策略为您提供了如何表示null的灵活性。

您可以将类修改为如下所示:

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,对于此属性,您希望将此属性的空元素视为null。

对于这个XML:

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

requiredBooks 属性将解组为:null,aBook,null。

目前有一个错误阻止我们正在解决此问题。您可以在此处跟踪此问题的进展情况:

答案 2 :(得分:2)

嗯,我发现了一种方法,虽然我觉得它不太优雅。

修改:实际上,下方的解决方案无法正常运行。它实际上不会导致任何条目被添加到列表中,无论它们是空元素还是完全由数据构成。

也许我做错了,所以欢迎任何评论。

我创建了一个处理转换的适配器,并使用注释通知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;
    }
}

它按照我的意愿行事,但正如我先前所说,我不相信它的优雅。
修改:如上所述,这不起作用,但可能是由于我的一些错误。

答案 3 :(得分:1)

试试这个,

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

答案 4 :(得分:1)

我做了类似的淤泥:

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

答案 5 :(得分:0)

我有类似的问题 - 我需要处理包含接口的ArrayList。我刚刚创建了一个接口适配器(MyInterfaceAdapter)并注释了List:

@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(甚至是空的)。

我认为在上面提到的问题中,可以添加其他条件,并在空书的情况下返回null。另一方面,我也不喜欢返回null。