JAXB Wrapped通用对象的Setter方法永远不会被调用

时间:2015-12-30 15:36:10

标签: java xml generics null jaxb

我正在尝试解组一个名为Key的泛型类的ArrayList。

Key有setValue()方法,它接收一个通用参数。

密钥类

@XMLRootElement(name = "Key")
public class Key<T>{

    @XMLElement(name = "Key")
    public setKey(T value){
    this.value = value
    }
}

特定的ArrayList

@XMLElementWrapper(name = "Keys")
@XMLElement(name = "Key")
public setKeys(ArrayList<Key> keys){
this.keys = keys;
}

这部分XML文件

<Keys>
    <Key>2</Key>
</Keys>

运行代码将创建ArrayList,并且WILL中将包含一个Key对象。 但是Key将是Null。

(我试过调试,可能会注意到它没有调用类的setKey()setter)

与它的通用事实有什么关系? 提前谢谢。

修改

在过去的一天,我调试了很多,我现在可以说问题在于,在实例化ArrayList之后,在XML中创建每个Key Key的每个Key时,unmarshaller使用Key的空构造函数只是从不调用它的setter,因此我有一个包含键的ArrayList,它们的值为&#39;数据成员是null

任何人都可以解释我做错了什么吗?为什么setter没有被调用?

谢谢。

1 个答案:

答案 0 :(得分:0)

你可能运气不好。 unmarshaller如何知道2是一个整数,而不是一个double或long或一个时间戳或一些其他类可以解析2自定义适配器。

你想要的注释基本上是下面的(减去我稍后会解释的@XmlJavaTypeAdapter)但是如果你尝试在没有适配器的情况下运行该代码,你将得到NullPointerException,因为JAXB无法处理对象上的@XmlValue注释(这是对待T的方式)。 JAXB无法处理它的原因是因为它无法知道对象是什么。

现在,如果您有自己的自定义规则来确定T的类型(例如,当来自XML T时,它总是一个整数,或者如果它不包含&#39,则T是一个整数。&#然后你可以使用适配器实现你自己的逻辑,这是我在下面演示的(我使用了第二条规则)。

@XmlRootElement(name="root")
public class SO {

    private List<Key<?>> keys;

    @XmlElementWrapper(name="Keys")
    @XmlElement(name="Key")
    public void setKeys(List<Key<?>> keys) {
        this.keys = keys;
    }

    public List<Key<?>> getKeys() {
        return keys;
    }

    @XmlType
    public static class Key<T> {

        private T val;

        @XmlValue
        @XmlJavaTypeAdapter(ToStringAdapter.class)
        public void setKey(T val) {
            this.val = val;
        }

        public String toString() {
            return "Key(" + val + ")";
        }

    }

    public static class ToStringAdapter extends XmlAdapter<String, Object> {

        @Override
        public Object unmarshal(String v) throws Exception {
            if(v.contains(".")) {
                return Double.parseDouble(v);
            } else {
                return Integer.parseInt(v);
            }
        }

        @Override
        public String marshal(Object v) throws Exception {
            return v.toString(); //Will never be called anyway so you could also throw an exception here
        }

    }

    private static final String XML_INT = "<root><Keys><Key>2</Key></Keys></root>";
    private static final String XML_DOUBLE = "<root><Keys><Key>2.7</Key></Keys></root>";

    public static void main(String [] args) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(Key.class, SO.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        SO so = (SO) unmarshaller.unmarshal(new StringReader(XML_INT));
        System.out.print(so.keys);
        System.out.println(" " + so.keys.get(0).val.getClass().getSimpleName());
        so = (SO) unmarshaller.unmarshal(new StringReader(XML_DOUBLE));
        System.out.print(so.keys);
        System.out.println(" " + so.keys.get(0).val.getClass().getSimpleName());
    }

}