Java JAXB包装的通用对象';s Setter方法从未调用

Java JAXB包装的通用对象';s Setter方法从未调用,java,xml,generics,null,jaxb,Java,Xml,Generics,Null,Jaxb,我正在尝试解组一个名为Key的泛型类的ArrayList 该键具有接收泛型参数的setValue()方法 关键类 @XMLRootElement(name=“Key”) 公开类密钥{ @xmlement(name=“Key”) 公共设置密钥(T值){ this.value=value } } 特定数组列表 @xmlementwrapper(name=“Keys”) @xmlement(name=“Key”) 公共设置键(ArrayList键){ this.keys=keys; } 这是XML

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

该键具有接收泛型参数的setValue()方法

关键类
@XMLRootElement(name=“Key”)
公开类密钥{
@xmlement(name=“Key”)
公共设置密钥(T值){
this.value=value
}
}
特定数组列表
@xmlementwrapper(name=“Keys”)
@xmlement(name=“Key”)
公共设置键(ArrayList键){
this.keys=keys;
}
这是XML文件的一部分

2.
运行该代码将创建ArrayList,并在其中包含一个Key对象。 但密钥将为空

(我尝试过调试,但发现它没有调用该类的setKey()setter)

这和它的通用性有关吗? 提前谢谢

编辑 在过去的一天中,我已经调试了很多,现在我可以说问题在于,在实例化ArrayList之后,当在XML中为每个键标记创建每个键时,解组器使用键的空构造函数,并且从不调用它的setter,因此,我有一个ArrayList,其中包含键的“value”数据成员为
null

谁能解释一下我做错了什么?为什么二传手没有接到电话


谢谢。

你可能运气不好。解组器如何知道2是一个整数,而不是一个double、long、timestamp或其他具有自定义适配器的类,该适配器可以将2解析为自身

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

现在,如果您有自己的自定义规则来确定T的类型(例如,当来自XML时,T始终是一个整数,或者如果它不包含“.”和双精度,则T是一个整数),那么您可以使用适配器实现自己的逻辑,这是我在下面演示的(我使用了第二个规则)

@XmlRootElement(name=“root”)
公开课{

private List我有点困惑,您的示例中的值字段2是吗?您是否需要@XmlValue注释才能获取您发布的示例XML?@Pace,Key类包含一个值数据成员,这是它的“setter”?非常感谢!您能向我解释一下这个适配器的作用以及为什么它会进入现在设置器?关键更改是将
@XmlElement
更改为
@XmlValue
@XmlElement
注释表示子节点是元素节点(例如
),而
@XmlValue
注释表示子节点是文本节点(例如2)。因为XML在
元素下面没有任何元素(2是文本,不是元素)它没有调用该setter。通过添加
@XmlValue
,它随后调用了setter。适配器仅用于帮助JAXB确定文本应转换到的Java类型。
@XMLRootElement(name = "Key")
public class Key<T>{

    @XMLElement(name = "Key")
    public setKey(T value){
    this.value = value
    }
}
@XMLElementWrapper(name = "Keys")
@XMLElement(name = "Key")
public setKeys(ArrayList<Key> keys){
this.keys = keys;
}
<Keys>
    <Key>2</Key>
</Keys>
@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());
    }

}