【发布时间】:2012-11-07 15:01:12
【问题描述】:
假设我有两个 JavaBeans Person 和 Address。
如果我创建一个 Person 对象列表,我想编组如下:
<persons>
<person>...</person>
</persons>
可以使用此处描述的技术: Using JAXB to unmarshal/marshal a List<String>
通过使用@XmlRootElement(name = "persons") 和@XmlElement(name = "person") 注释JaxbList,就可以编组到上面的XML。
但是,如果能够重用相同的JaxbList<T> 类来编组Address 对象列表,那就太好了。实际上,我会有很多其他类型的豆子。我可以选择类似的东西:
<list>
<item xsi:type="person" xmlns:xsi="http://www.w2.org/2001/XmlSchema-instance"></item>
</list>
但是,理想情况下,最好将“list”替换为类名的复数形式,将“item”替换为类名。
那么,是否可以在运行时以编程方式配置 JaxbContext 或其他东西,并在 @XmlRootElement 和 @XmlElement 中设置 name 的值?
或者任何其他方式来获得这个工作,而不必为每个 bean 类型编写 JaxbList 的单独实现?也许 XmlJavaTypeAdapter 可以实现这种事情?
更新 @Blaise Doughan 下面接受的解决方案效果很好。对于我的用例,我需要直接从 Java 对象转到 XML,这就是有效的方法(注意这不是我的完整实现,它只是用于演示的伪代码):
//JAXBContext is thread safe and so create it in constructor or
//setter or wherever:
...
JAXBContext jc = JAXBContext.newInstance(Wrapper.class, clazz);
...
public String marshal(List<T> things, Class clazz) {
//configure JAXB and marshaller
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
//Create wrapper based on generic list of objects
Wrapper<T> wrapper = new Wrapper<T>(things);
JAXBElement<Wrapper> wrapperJAXBElement = new JAXBElement<Wrapper>(new QName(clazz.getSimpleName().toLowerCase()+"s"), Wrapper.class, wrapper);
StringWriter result = new StringWriter();
//marshal!
m.marshal(wrapperJAXBElement, result);
return result.toString();
}
【问题讨论】:
-
在你的更新中,因为
JAXBContext是线程安全的,如果你能够缓存它而不是为每个marshal操作创建一个新的,你会看到更好。 -
是的,好点,我使用它的真正实现是缓存的,我缩写了答案。但可能应该花时间补充一下吧?我马上更新。
-
您可能希望将该代码 sn-p 中的
toLowerCase()更改为您最喜欢的decapitalize()实现。