下面的代码曾经在JDK 1.7使用的JAXB实现下工作,但现在在JDK 1.8下它已经破解了。在下面的代码中,您将找到似乎使其在1.8中工作的关键更改。 1.8下的“修复”并不是真正的修复,因为暴露内部集合以供外部世界直接修改是不好的做法。我想通过我的类控制对内部列表的访问,我不想通过创建可观察的集合并听取它们来使事情复杂化。这是不可接受的。
有没有办法让我的原始代码在JD 1.8的JAXB下工作?
@XmlElementWrapper(name = "Wrap")
@XmlElement(name = "Item", required = true)
public synchronized void setList(List<CustomObject> values) {
list.clear();
list.addAll(values);
}
public synchronized List<CustomObject> getList() {
// return new ArrayList(list); // this was the original code that worked under 1.7
return list; //this is the only thing that works under 1.8
}
经过更多分析后,问题似乎来自于JAXB,而不再为集合调用setter方法(它曾经在JDK 1.7下使用过)。现在在JDK 1.8下,它调用getter并直接修改集合。这带来了几个问题:
1 - 强制用户将内部集合暴露给外界进行免费修改(不良做法) 2 - 不允许用户在列表更改时执行任何自定义代码(例如,如果调用setter,您可以执行此操作)。有可能创建一个可观察的集合并听取它,但这是一个比调用setter方法更复杂的解决方法。
答案 0 :(得分:2)
当在JAXB中映射集合属性时,它首先检查getter以查看collection属性是否已预先初始化。在下面的示例中,我希望将我的属性公开为List<String>
,但支持实现为LinkedList
,可以容纳1000个项目。
private List<String> foos = new LinkedList<String>(1000);
@XmlElement(name="foo")
public List<String> getFoos() {
return foos;
}
如果您以前让JAXB在映射到从getter返回非null响应的集合的属性上调用setter,则该JAXB实现中存在错误。您的代码也不应该在以前的版本中有效。
让setter调用你只需要让你的getter在对象的新实例上返回null。您的代码可能类似于:
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlRootElement(name = "Foo")
public class Foo {
private List<CustomObject> list = null;
@XmlElementWrapper(name = "Wrap")
@XmlElement(name = "Item", required = true)
public synchronized void setList(List<CustomObject> values) {
if (null == list) {
list = new ArrayList<CustomObject>();
} else {
list.clear();
}
list.addAll(values);
}
public synchronized List<CustomObject> getList() {
if (null == list) {
return null;
}
return new ArrayList(list);
}
}
如果您不需要在JAXB解组返回的List上执行任何逻辑,那么使用字段访问可能是一种可接受的解决方案。
@XmlRootElement(name = "Foo")
@XmlAccessorType(XmlAccessType.FIELD)
public class Foo {
@XmlElementWrapper(name = "Wrap")
@XmlElement(name = "Item", required = true)
private List<CustomObject> list = null;
public synchronized void setList(List<CustomObject> values) {
if(null == list) {
list = new ArrayList<CustomObject>();
} else {
list.clear();
}
list.addAll(values);
}
public synchronized List<CustomObject> getList() {
return new ArrayList(list);
}
}