OpenJDK 8下JAXB+SAX解析XML遇Connection Reset异常求助
问题:OpenJDK 8下JAXB反序列化XML出现SSL连接重置异常
我先从网络下载XML报告并将原始XML存入String变量,随后创建SAXParser的代码如下:
try { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setXIncludeAware(true); spf.setNamespaceAware(true); spf.setValidating(true); // Not required for JAXB/XInclude XMLReader xr = (XMLReader) spf.newSAXParser().getXMLReader(); xr.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); //with true report could not be parsed xr.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); // This may not be strictly required as DTDs shouldn't be allowed at all, per previous line. xr.setFeature("http://xml.org/sax/features/external-general-entities", false); xr.setFeature("http://xml.org/sax/features/external-parameter-entities", false); return new SAXSource(xr, new InputSource(new StringReader(output))); } catch (Exception e) { e.printStackTrace(); }
接着调用JAXB反序列化方法:
jaxbUnmarshaller.unmarshal(saxSource);
触发了如下异常,经查ClassLoader为null。该代码在Oracle Java 8下可正常运行,但在OpenJDK version "1.8.0_392"中出现问题。
异常信息:
JAXP: find factoryId =javax.xml.parsers.SAXParserFactory JAXP: loaded from fallback value: com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl JAXP: created new instance of class com.sun.org.apache.xerces.internal.jaxp.SAXParserFactoryImpl using ClassLoader: null javax.xml.bind.UnmarshalException - with linked exception: [javax.net.ssl.SSLException: Connection reset] at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:246) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:214) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:140) at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:123) at com.matrix.clientmanager.ws.nipr.ScbDownloadReport.downloadReport(ScbDownloadReport.java:74) at com.matrix.clientmanager.autobatch.RunLicenseConfig.checkReportResults(RunLicenseConfig.java:325) at com.matrix.clientmanager.autobatch.RunLicenseConfig.<init>(RunLicenseConfig.java:87) at com.matrix.clientmanager.autobatch.AutoBatch.runLicenseConfig(AutoBatch.java:3352) at com.matrix.clientmanager.autobatch.RunAutoBatch.main(RunAutoBatch.java:1111) Caused by: javax.net.ssl.SSLException: Connection reset at sun.security.ssl.Alert.createSSLException(Alert.java:127) at sun.security.ssl.TransportContext.fatal(TransportContext.java:331) at sun.security.ssl.TransportContext.fatal(TransportContext.java:274) at sun.security.ssl.TransportContext.fatal(TransportContext.java:269) at sun.security.ssl.SSLTransport.decode(SSLTransport.java:138) at sun.security.ssl.SSLSocketImpl.decode(SSLSocketImpl.java:1401) at sun.security.ssl.SSLSocketImpl.readHandshakeRecord(SSLSocketImpl.java:1309) at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:440) at sun.net.www.protocol.https.HttpsClient.afterConnect(HttpsClient.java:559) at sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:197) at sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1572) at sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1500) at sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:268) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.setupCurrentEntity(XMLEntityManager.java:648) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startEntity(XMLEntityManager.java:1305) at com.sun.org.apache.xerces.internal.impl.XMLEntityManager.startDTDEntity(XMLEntityManager.java:1271) at com.sun.org.apache.xerces.internal.impl.XMLDTDScannerImpl.setInputSource(XMLDTDScannerImpl.java:264) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.dispatch(XMLDocumentScannerImpl.java:1160) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$DTDDriver.next(XMLDocumentScannerImpl.java:1044) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:958) at com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:601) at com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112) at com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:504) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:841) at com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:770) at com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141) at com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1213) at com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:642) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:243) ... 8 more Suppressed: java.net.SocketException: Broken pipe (Write failed) at java.net.SocketOutputStream.socketWrite0(Native Method) at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:111) at java.net.SocketOutputStream.write(SocketOutputStream.java:155) at sun.security.ssl.SSLSocketOutputRecord.encodeAlert(SSLSocketOutputRecord.java:81) at sun.security.ssl.TransportContext.fatal(TransportContext.java:362) ... 35 more Caused by: java.net.SocketException: Connection reset at java.net.SocketInputStream.read(SocketInputStream.java:210) at java.net.SocketInputStream.read(SocketInputStream.java:141) at sun.security.ssl.SSLSocketInputRecord.read(SSLSocketInputRecord.java:464) at sun.security.ssl.SSLSocketInputRecord.decode(SSLSocketInputRecord.java:165) at sun.security.ssl.SSLTransport.decode(SSLTransport.java:109) ... 32 more
问题根源
从异常栈可见,解析器尝试加载外部DTD时发起了HTTPS请求,导致连接重置。虽然配置了load-external-dtd为false,但开启setValidating(true)且disallow-doctype-decl设为false后,OpenJDK的Xerces实现仍会触发DTD解析逻辑,再加上ClassLoader为null影响了SSL上下文初始化,最终导致连接失败。
修复方案
- 关闭XML验证:注释已说明验证非JAXB/XInclude必需,直接关闭验证避免触发DTD解析:将
spf.setValidating(true)改为false。 - 显式设置ClassLoader:创建SAXParserFactory时指定当前线程上下文类加载器,避免出现null ClassLoader:
spf.setClassLoader(Thread.currentThread().getContextClassLoader()); - 强化外部资源禁用配置:额外添加禁用DTD语法加载的feature,彻底阻止外部资源请求。
修改后的完整代码
try { SAXParserFactory spf = SAXParserFactory.newInstance(); spf.setClassLoader(Thread.currentThread().getContextClassLoader()); // 显式设置类加载器 spf.setXIncludeAware(true); spf.setNamespaceAware(true); spf.setValidating(false); // 关闭验证,避免触发DTD解析 XMLReader xr = spf.newSAXParser().getXMLReader(); xr.setFeature("http://apache.org/xml/features/disallow-doctype-decl", false); xr.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false); xr.setFeature("http://apache.org/xml/features/nonvalidating/load-dtd-grammar", false); // 额外禁用DTD语法加载 xr.setFeature("http://xml.org/sax/features/external-general-entities", false); xr.setFeature("http://xml.org/sax/features/external-parameter-entities", false); return new SAXSource(xr, new InputSource(new StringReader(output))); } catch (Exception e) { e.printStackTrace(); }
补充说明
OpenJDK与Oracle JDK的Xerces实现存在细微差异,对验证和外部资源加载的处理逻辑不一致,这是兼容性问题的核心。若仍需XML结构校验,建议改用Schema验证(spf.setSchema(...)),避免依赖DTD带来的外部资源加载风险。
内容的提问来源于stack exchange,提问作者user2654788
相关产品推荐
相关产品推荐

