JAXB 配置因集合从 JDK 1.7 升级到 JDK 1.8 u05 而被破坏 [英] JAXB Configuration was broken by upgrading from JDK 1.7 to JDK 1.8 u05 for collections

查看:27
本文介绍了JAXB 配置因集合从 JDK 1.7 升级到 JDK 1.8 u05 而被破坏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

下面的代码曾经在 JDK 1.7 使用的 JAXB 实现下工作,但现在在 JDK 1.8 下它被破坏了.在下面的代码中,您会发现似乎使它在 1.8 中工作的关键更改.1.8 下的修复"并不是真正的修复,因为将内部集合公开以供外部世界直接修改是不好的做法.我想通过我的班级控制对内部列表的访问,我不想通过制作可观察的集合并收听它们来使事情复杂化.这是不可接受的.

The code below used to work under the JAXB implementation used by JDK 1.7, but now under JDK 1.8 it's broken. In the code below you will find the key change that seems to make it work in 1.8. The "fix" under 1.8 is not really a fix because it's bad practice to expose internal collections for direct modification by the outside world. I want to control access to the internal list through my class and I don't want to complicate things by making observable collections and listening to them. This is not acceptable.

有没有办法让我的原始代码在 JD 1.8 的 JAXB 下工作?

Is there any way to get my original code to work under the JAXB of JD 1.8?

 @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 并直接修改集合.这带来了几个问题:

After more analysis, the problem seems to be coming from JAXB not calling the setter method for collections anymore (it used to under JDK 1.7). Now under JDK 1.8, it calls the getter and modifies the collection directly. This poses several problems:

1-强制用户将内部集合公开给外部世界以供自由修改(不好的做法)2-不允许用户在列表更改时执行任何自定义代码(例如调用 setter 时可以执行的操作).可能可以创建一个可观察的集合并监听它,但这是一个比仅调用 setter 方法复杂得多的解决方法.

1-forces the user to expose an internal collection to the outside world for free modification (bad practice) 2-doesn't allow the user to do any custom code when the list changes (such as what you could do if the setter was called). It might be possible to make an observable collection and listen to it, but this is a much more complicated workaround than just calling the setter method.

推荐答案

背景

在 JAXB 中映射集合属性时,它首先检查 getter 以查看集合属性是否已预先初始化.在下面的示例中,我希望将我的属性公开为 List,但支持实现是一个准备好容纳 1000 个项目的 LinkedList.

Background

When a collection property is mapped in JAXB it first checks the getter to see if the collection property has been pre-initialized. In the example below I want to have my property exposed as List<String>, but have the backing implementation be a LinkedList ready to hold 1000 items.

private List<String> foos = new LinkedList<String>(1000);

@XmlElement(name="foo")
public List<String> getFoos() {
    return foos;
}

为什么你的代码过去可以工作

如果您之前让 JAXB 对映射到集合的属性调用 setter,该集合从 getter 返回非空响应,那么该 JAXB 实现中存在错误.您的代码也不应该在以前的版本中运行.

Why Your Code Used to Work

If you previously had JAXB call the setter on a property mapped to a collection that returned a non-null response from the getter, then there was a bug in that JAXB implementation. Your code should not have worked in the previous version either.

要调用 setter,您只需让 getter 在对象的新实例上返回 null.您的代码可能类似于:

To have the setter called you just need to have your getter return null, on a new instance of the object. Your code could look something like:

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 执行任何逻辑,那么使用字段访问可能是一个可以接受的解决方案.


UPDATE

If you don't need to perform any logic on the List returned from JAXB's unmarshalling then using field access may be an acceptable solution.

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

}

这篇关于JAXB 配置因集合从 JDK 1.7 升级到 JDK 1.8 u05 而被破坏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆