Java JAXB解组;“通用”;真实世界文档

Java JAXB解组;“通用”;真实世界文档,java,jaxb,unmarshalling,Java,Jaxb,Unmarshalling,我们有一大套这种风格的配置文档 <foo> <bar class="com.diedel.Gnarf"> ...more content </bar> <bar class="de.doedel.Bork"> ..more content </bar> ... </foo> …更多内容 …更多内容 ... 通用实现类都使用Jaxb本身进行映射 在我最后回到Xstream之前,我向社区

我们有一大套这种风格的配置文档

<foo>
  <bar class="com.diedel.Gnarf">
    ...more content
  </bar>
  <bar class="de.doedel.Bork">
    ..more content
  </bar>
  ...
</foo>

…更多内容
…更多内容
...
通用实现类都使用Jaxb本身进行映射

在我最后回到Xstream之前,我向社区提出了一个问题:是否有一种(非黑客的)方法可以在Jaxb中对其进行解密。到目前为止,我们尝试的是使用@XMLAdapter进行“嵌套”解组,其中“bar”字段获取一个元素,获取目标类并调用另一个“解组”循环。这种方法a)相当缓慢,b)随着切换到Java 7而中断,在Java 7中,一些神奇的ThreadLocal在从内部解组器返回时会破坏上下文

我发现MOXy可以使用@XmlDiscriminatorNode来支持这一点——这看起来是一个很好的解决方案,我真的很喜欢Blaise的非常好的输入——但是仅仅为了好玩而添加一个>7MB的库不是一个选项


其他想法?

如果结构真的那么简单,我会尝试自己使用
XMLStreamReader
解析最上面的两个级别(foo和bar的class属性),然后将读取器交给JAXB解组器来解析每个条,将结果组合成一个列表。我不会费心直接使用JAXB解析外层信封层。

您可以使用and执行以下操作:

演示

可以使用StAX
XMLStreamReader
解析XML文档。您可以使用它前进到
元素,然后可以读取
属性,并从
类加载器
加载适当的Java类。然后,您可以利用一个采用类参数的
解组方法

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();
        }
    }

}
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

下面是我在这个示例中使用的示例文档,它基于您的问题中的文档。我更改了包名

<?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>

+你比我先得到答案。如果您想知道这种方法的impl是什么样子,请查看:感谢您的快速响应。由于您的答案与@Blaise one非常相似,我只评论一次……MOXy的
@xmlDescriptionatorNode
扩展对于映射继承关系非常有用()。如果使用捆绑包而不是包含JPA和SDO实现的整个
eclipselink.jar
,MOXy的安装占用空间会更小。我个人正在进一步减少足迹,您可以使用以下错误跟踪我的进度:再次感谢您的快速和非常详细的响应。尽管如此,我必须补充一点,那就是确实需要一种通用的方法。首先,它更复杂,属性也在其上编组。第二,“泛型”实例化在许多地方和任何嵌套深度。但您的答案指向了另一个选项:我应该能够使用sax过滤器来实现这一点,该过滤器将class=“x.y.Z”映射到xsi:type=“Z”?@mtraut-是的,您可以使用sax过滤器。这里有一个链接,指向我的一个可能有助于这种方法的答案:嗯,我将尝试一下(尽管它仍然有黑客的味道)。有没有一种简单的方法可以让完全限定的类名保持活力?我会给这个答案以奖励,尽管如此,我还是认可@Ian给出的几乎相同的建议。但你总是投入大量的工作。谢谢你。
<?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>
Gnarf(a=123)
Bork(b=Hello World)