繁体   English   中英

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

[英]Transforming empty element into null when unmarshalling with JAXB

使用以下JAXB注释定义类:

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

解组包含此文档的XML文档时

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

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

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

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

EclipseLink JAXB(MOXy)中,我们有一个null策略的概念。 此null策略为您提供了如何表示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。

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

好吧, 我找到了一种方法,虽然我发现它并不优雅。

编辑:实际上,下面的解决方案无法正常工作。 实际上它不会将任何条目添加到列表中,无论它们是空元素还是完全由数据构成。

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

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

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

我做了类似的淤泥:

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

试试这个,

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

我有类似的问题 - 我需要处理包含接口的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。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM