使用以下JAXB注释定义类:
class Course {
@XmlElement (name = "book")
List<Book> requiredBooks = new ArrayList<Book>();
解组包含此
的XML文档时<course>
...
<book/>
</course>
我最终将一本书添加到列表中,其所有属性都设置为null。我不控制XML输入。如何防止添加此空白书?我尝试拦截set ..()或添加..()方法,但是在处理集合时,JAXB绕过了setter。有什么建议吗?
答案 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。