JAXB解组“泛型”现实世界的文件 [英] JAXB unmarshalling of "generic" real world documents
问题描述
我们有一大堆风格的配置文件
We have a large set of configuration documents of the style
<foo>
<bar class="com.diedel.Gnarf">
...more content
</bar>
<bar class="de.doedel.Bork">
..more content
</bar>
...
</foo>
通用实现类都是使用Jaxb自己映射的。
The generic implementation classes are all mapped using Jaxb themselves.
在我最终回归到Xstream之前,向社区提出一个问题:是否有一种(非黑客)方式可以在Jaxb中解组。到目前为止我们尝试使用@XMLAdapter进行嵌套解组,其中bar字段获取Element,获取目标类并调用另一个unmarshall循环。这种方法已经a)非常缓慢,并且b)在切换到Java 7时被破坏,其中一些神奇的ThreadLocal在从内部unmarshall返回时破坏了上下文。
Before i finally revert to Xstream, a question to the community: Is there a (non hack) way to get this unmarshalled in Jaxb. What we tried so far is "nested" unmarshalling using an @XMLAdapter, where the "bar" field gets an Element, gets the target class and calls another "unmarshall" cycle. This approach has been a) quite slow and b) is broken with the switch to Java 7 where some magic ThreadLocal destroys the context when returning from the inner unmarshall.
我发现MOXy可以使用@XmlDiscriminatorNode来支持这个 - 这看起来是一个很好的解决方案,我非常喜欢Blaise的非常好的输入 - 但是为了好玩而添加> 7MB的lib不是一种选择。
I found that MOXy may support this using @XmlDiscriminatorNode - this looks like a good solution and i really like the very good input of Blaise - but adding a >7MB lib just for fun is not an option.
其他想法?
推荐答案
您可以使用 JAXB(JSR-222) 和 StAX(JSR-173) :
You could do something like the following with JAXB (JSR-222) and StAX (JSR-173):
演示
可以使用StAX XMLStreamReader
来解析XML文档。您可以使用它前进到 bar
元素,然后您可以读取类
属性并加载相应的Java类来自 ClassLoader
。然后你可以利用一个带有类参数的 unmarshal
方法。
A StAX XMLStreamReader
can be used to parse the XML document. You can use it to advance to a bar
element, then you can read the class
attribute and load the appropriate Java class from a ClassLoader
. Then you can leverage one of the unmarshal
methods that takes a class parameter.
package forum12402215;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.transform.stream.StreamSource;
public class Demo {
public static void main(String[] args) throws Exception {
ClassLoader classLoader = Bork.class.getClassLoader();
JAXBContext jc = JAXBContext.newInstance(Bork.class, Gnarf.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
StreamSource source = new StreamSource("src/forum12402215/input.xml");
XMLInputFactory xif = XMLInputFactory.newFactory();
XMLStreamReader xsr = xif.createXMLStreamReader(source);
xsr.nextTag(); // Advance to "foo" element
xsr.nextTag(); // Advance to "bar" element
while(xsr.getLocalName().equals("bar")) {
String className = xsr.getAttributeValue("", "class");
Class<?> clazz = classLoader.loadClass(className);
Object object = unmarshaller.unmarshal(xsr, clazz).getValue();
System.out.println(object);
xsr.nextTag();
}
}
}
Bork
下面是一个示例 Bork
类。
package forum12402215;
public class Bork {
private String b;
public String getB() {
return b;
}
public void setB(String b) {
this.b = b;
}
@Override
public String toString() {
return "Bork(b=" + b + ")";
}
}
Gnarf
下面是一个示例 Gnarf
类:
package forum12402215;
public class Gnarf {
private int a;
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
@Override
public String toString() {
return "Gnarf(a=" + a + ")";
}
}
input.xml
以下是我根据您的问题使用的示例文档。我更改了包名。
Below is he sample document I used used for this example based on the one from your question. I changed the package names.
<?xml version="1.0" encoding="UTF-8"?>
<foo>
<bar class="forum12402215.Gnarf">
<a>123</a>
</bar>
<bar class="forum12402215.Bork">
<b>Hello World</b>
</bar>
</foo>
输出
以下是运行演示代码的输出。
Below is the output from running the demo code.
Gnarf(a=123)
Bork(b=Hello World)
这篇关于JAXB解组“泛型”现实世界的文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!