我正在尝试解组一个名为Key的泛型类的ArrayList。
Key有setValue()方法,它接收一个通用参数。
@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>
运行代码将创建ArrayList,并且WILL中将包含一个Key对象。 但是Key将是Null。
(我试过调试,可能会注意到它没有调用类的setKey()setter)
与它的通用事实有什么关系? 提前谢谢。
在过去的一天,我调试了很多,我现在可以说问题在于,在实例化ArrayList之后,在XML中创建每个Key Key的每个Key时,unmarshaller使用Key的空构造函数只是从不调用它的setter,因此我有一个包含键的ArrayList,它们的值为&#39;数据成员是null
。
任何人都可以解释我做错了什么吗?为什么setter没有被调用?
谢谢。
答案 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());
}
}