我有一段 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
正在保留 完成解码后的一些资源? - 线程安全?参见这篇关于“JAXB creating context and 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 文件,问题就解决了!
谢谢大家!节日快乐!
关于java - JAXB 解码在一台机器上失败,但在其他机器上失败/也在单元测试中工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41308531/