我有一段看起来像这样的JAXB解组代码:
Foo foo = null;
try {
logger.debug(methodNamePrefix + "xmlString is \n" + xmlString);
JAXBContext jaxbContext = JAXBContext
.newInstance(Foo.class);
Unmarshaller u = jaxbContext.createUnmarshaller();
u.setEventHandler(new DefaultValidationEventHandler());
StreamSource streamsource = new StreamSource(new StringReader(xmlString));
foo = (Foo) u.unmarshal(streamsource);
sanityCheckDbpAfterUnmarshalling(xmlString, foo);
}catch(Exception e){
throw new AnalysisNotPossibleException();
}
if (foo==null){
throw new AnalysisNotPossibleException();
}
这段代码已经使用了几个月,直到最近,在一台机器上,它开始失败。当它失败时,它会发出看似合法的抱怨-除了在另一台机器上甚至在同一台机器上但在单元测试中运行时,具有相同输入xmlString的同一段代码不会抱怨:
javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"entry"). Expected elements are (none)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:642)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:254)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:249)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:116)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.childElement(Loader.java:101)
at com.sun.xml.bind.v2.runtime.unmarshaller.StructureLoader.childElement(StructureLoader.java:243)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:478)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:459)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:148)
我非常确定这是由于该计算机的某些本地环境引起的,但是我无法弄清楚那是什么。我尝试在Eclipse中清理所有二进制文件。
我知道这需要调试,并且我不希望得到完整的答案。但是,对于任何其他可以检查的内容,我将不胜感激。谢谢!
更新
Foo类如下所示:
@XmlRootElement
public class Foo implements Serializable{
private static final long serialVersionUID = -4550266352252980254L;
@XmlElement
private HashMap<String, SomeProperty> mapAllPortletProperty =
new HashMap<String, SomeProperty>();
...
XML字符串如下所示
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<foo>
<mapAllPortletProperty>
<entry>
<key>Portlet 6262</key>
<value>
<apIdStrAtBirth>4536</apIdStrAtBirth>
...
第二次更新
感谢到目前为止的所有帮助。那帮助我考虑了这些
两个方面:
资源泄漏?
StreamSource
和StringReader
保持完成解组后的一些资源?
线程安全? c.f.这样的关于“ JAXB creating contextand marshallers cost”的帖子
对于#1,我检查了是否似乎没有资源泄漏。
我也有一个压力测试程序,它进行了大量的编组工作。我没有发现该程序的内存占用量不断增加。
对于#2,我重写了代码,以便对于每个需要的类
要解组,我的代码仅实例化
JAXBContext
一次。不幸的是,有了以上新见解,我仍然无法
找到问题的根本原因。欢迎有任何见识!
最佳答案
经过大量调试后,我找到了问题的原因。
在我的一个文件夹中,有两个与JAXB相关的JAR文件:
$ find . -name "jaxb*" -exec ls -l {} \;
-rwx------+ 1 leecy None 89967 Mar 19 2014 ./war/WEB-INF/lib/jaxb-api-2.1.jar
-rwx------+ 1 leecy None 876610 Mar 19 2014 ./war/WEB-INF/lib/jaxb-impl-2.1.13.jar
我认为JVM已经提供了JAXB的参考实现(我正在使用Oracle / Sun的JDK 1.7.0_51),我们不需要这些多余的JAR文件,对吗?它们的存在实际上可能会使我的程序感到困惑,并导致加载另一个
JAXBContextImpl
。由于某种原因,这种实现无法解组XML文件。受此blog post的启发,我让程序在实例化后打印出实现的确切类名,并得到以下结果:
如果我删除了多余的JAR文件,我的程序将这一行打印出来,解组将起作用:
getJcMap(): Just instantiated an JAXBContext: class com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl
如果我把它们留在里面,我的程序会打印出来,解组将失败:
getJcMap(): Just instantiated an JAXBContext: class com.sun.xml.bind.v2.runtime.JAXBContextImpl
这就解释了为什么仅在具有特定项目文件夹的特定计算机上而不在其他环境下发生问题的原因。
所以我删除了那些多余的JAR文件,问题解决了!
感谢大家!节日快乐!