从PDF提取XML并JAXB反序列化报错:Buffer already closed(OpenShift环境)
问题:OpenShift部署后JAXB反序列化报错“java.io.IOException: Buffer already closed”
本地IntelliJ运行正常,但部署到OpenShift集群的JAR包执行时,通过Apache PDFBox从PDF提取XML片段后,JAXB反序列化失败,报错java.io.IOException: Buffer already closed。
具体流程:从PDF中提取得到List<myObject>,后续通过JAXB完成反序列化,核心代码如下:
创建Unmarshaller的代码
try { JAXBContext context = JAXBContext.newInstance(typeClasse.getClass()); Unmarshaller unmarshaller = context.createUnmarshaller(); SchemaFactory factory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI); String xsdFilePath = getXSD(); Schema schema = factory.newSchema(this.getClass().getResource("/" + xsdFilePath)); unmarshaller.setSchema(schema); unmarshaller.setEventHandler(event -> false); return unmarshaller; } catch (JAXBException | SAXException e) { throw new UnmarshallException(e); }
其中typeClasse是反序列化的目标类,getXSD()返回资源文件夹中xsd目录下的根XSD文件路径(如"xsd/myparentXSD.xsd"),该XSD已引入同目录下其他XSD。
流式处理List的代码
myList.stream() .map(myObject -> unmarshallFichier(myObject, unmarshaller)) .collect(Collectors.toList());
反序列化方法实现
try { StreamSource stream = new StreamSource(myObject); JAXBElement<?> jaxbElement = unmarshaller.unmarshal(stream, typeClasse.getClass()); return (T) jaxbElement.getValue(); } catch (JAXBException e) { throw new UnmarshallException(e); }
排查方向与解决方案
1. Unmarshaller线程安全问题
JAXB的Unmarshaller实例不是线程安全的,流式处理stream().map(...)在OpenShift环境可能默认启用并行执行,多个线程共用同一个Unmarshaller会导致资源(Buffer)被提前关闭的冲突,本地环境可能因单线程执行未触发问题。
- 解决方案:在
map方法内部每次创建新的Unmarshaller实例,或者显式指定串行流(stream().sequential().map(...)),规范做法是避免复用Unmarshaller。
2. 类加载器与XSD资源加载异常
OpenShift中JAR包的类加载器和本地IDE存在差异,this.getClass().getResource("/" + xsdFilePath)可能无法正确加载XSD依赖文件(XSD内部引入的同目录文件),间接导致Unmarshaller处理时Buffer异常。
- 解决方案:
- 改用
getResourceAsStream加载XSD,或使用SchemaFactory.newSchema(Source[])显式传入所有依赖的XSD Source,避免依赖自动加载; - 确认Maven/Gradle打包配置,确保
src/main/resources/xsd下的所有XSD文件都被正确打入JAR包。
- 改用
3. PDFBox提取的流提前关闭
从PDF提取的myObject如果是InputStream类型,OpenShift环境中PDFBox的资源管理可能更严格,导致流被隐式关闭,反序列化时流已不可用。
- 解决方案:
- 提取XML片段时,将流内容复制到内存(如
ByteArrayInputStream),再传入反序列化方法,避免直接使用PDFBox返回的原始流; - 检查PDFBox代码,确保提取XML片段后流未被提前关闭。
- 提取XML片段时,将流内容复制到内存(如
内容的提问来源于stack exchange,提问作者Broshet
相关产品推荐
相关产品推荐

