在尝试迭代未编组对象列表时,我们遇到了一个非常难以追踪的问题,即我们看到ClassCastExceptions 有时。重要的一点是有时,重启后特定代码工作正常。这似乎指向了并发/时间/竞争条件的方向。我可以确认JAXBContext,marshallers和unmarshallers都没有被同时使用。我们已经通过锁定来序列化对它们的访问。
然而,由于我们在OSGi平台上运行,其中各个包通过Spring DM异步初始化,因此可能有两个不同的包同时创建其JAXBContext。
在任何情况下,我都会感谢任何可能导致这些间歇性 ClassCastExceptions的解释的指示。间歇性很重要,因为它们表明代码本身通常工作正常,但某些外部因素似乎会影响行为。
以下是异常的具体示例(注意我删除了公司特定的东西):
Caused by: java.lang.ClassCastException: com.sun.org.apache.xerces.internal.dom.ElementNSImpl cannot be cast to com.foobar.TunnelType
at com.foobar.NetMonitorImpl.getVpnStatus(NetMonitorImpl.java:180)
第180行的方法是for()构造循环遍历未编组对象内的TunnelType对象集合(所述解组工作正常BTW)。
鉴于实际的对象解组很好,JAXB在物理上是否可以将ElementNSImpl对象留在嵌套集合中?
运行时环境:
答案 0 :(得分:4)
只有当我忘记告诉JAXBContext时才会收到此异常 关于它可能正在处理的所有待编组类型。
JAXBContext.newInstance(MyClass1.class,MyClass2.class, [...]);
答案 1 :(得分:1)
这里建议的方法都没有为我做。但是这解决了我的问题
@XmlAnyElement(lax = true)
public List<Foo> foos;
答案 2 :(得分:0)
出于绝望,我们转向同步JAXBContext.class
对象,认为这是一些竞争条件的唯一剩余可能性,至少我们无法再次重现这个问题。这是关键代码:
synchronized (JAXBContext.class) {
context = JAXBContext.newInstance(packageList, classLoader);
}
答案 3 :(得分:0)
上面的synchronized子句也解决了我的问题,但似乎上下文不应该是局部变量。相反,它应该是实例变量,或静态。我无法重构我的代码我是如何喜欢的,所以我将上下文移动到静态初始化器中,这不是完美的,但似乎有效:
private static Unmarshaller um;
static{
try {
final JAXBContext ctx = JAXBContext.newInstance(ObjectFactory.class.getPackage().getName());
um = ctx.createUnmarshaller();
} catch (final JAXBException e) {
e.printStackTrace();
}
}