This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch karaf-4.4.x
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/karaf-4.4.x by this push:
new 2a4911b1b8 Remove static ThreadLocal caching in XmlUtils to prevent
ClassLoader leaks (#2532)
2a4911b1b8 is described below
commit 2a4911b1b89a4165e1d1c736d520770cd0293228
Author: JB Onofré <[email protected]>
AuthorDate: Wed Apr 15 17:42:22 2026 +0200
Remove static ThreadLocal caching in XmlUtils to prevent ClassLoader leaks
(#2532)
The static ThreadLocal fields holding DocumentBuilderFactory,
TransformerFactory
and SAXParserFactory pin the ClassLoader of the XML provider bundle on
long-lived
Karaf worker threads. When that bundle is updated or refreshed, the old
ClassLoader can never be GC'd, leading to zombie bundles and Metaspace
growth.
Create fresh factory instances per call instead of caching them. The public
API
is unchanged.
Fixes #2278
---
.../main/java/org/apache/karaf/util/XmlUtils.java | 98 +++++++++-------------
1 file changed, 39 insertions(+), 59 deletions(-)
diff --git a/util/src/main/java/org/apache/karaf/util/XmlUtils.java
b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
index 915dad5458..4c6acc006f 100644
--- a/util/src/main/java/org/apache/karaf/util/XmlUtils.java
+++ b/util/src/main/java/org/apache/karaf/util/XmlUtils.java
@@ -46,10 +46,6 @@ public class XmlUtils {
private static final Logger LOGGER =
LoggerFactory.getLogger(XmlUtils.class);
- private static final ThreadLocal<DocumentBuilderFactory>
DOCUMENT_BUILDER_FACTORY = new ThreadLocal<>();
- private static final ThreadLocal<TransformerFactory> TRANSFORMER_FACTORY =
new ThreadLocal<>();
- private static final ThreadLocal<SAXParserFactory> SAX_PARSER_FACTORY =
new ThreadLocal<>();
-
public static Document parse(String uri) throws TransformerException,
IOException, SAXException, ParserConfigurationException {
DocumentBuilder db = documentBuilder();
try {
@@ -106,74 +102,58 @@ public class XmlUtils {
}
public static XMLReader xmlReader() throws ParserConfigurationException,
SAXException {
- SAXParserFactory spf = SAX_PARSER_FACTORY.get();
- if (spf == null) {
- spf = SAXParserFactory.newInstance();
- spf.setNamespaceAware(true);
- spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
Boolean.TRUE);
-
spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
-
spf.setFeature("http://xml.org/sax/features/external-parameter-entities",
false);
-
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
- spf.setXIncludeAware(false);
- SAX_PARSER_FACTORY.set(spf);
- }
+ SAXParserFactory spf = SAXParserFactory.newInstance();
+ spf.setNamespaceAware(true);
+ spf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+ spf.setFeature("http://apache.org/xml/features/disallow-doctype-decl",
true);
+
spf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+
spf.setFeature("http://xml.org/sax/features/external-parameter-entities",
false);
+
spf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
+ spf.setXIncludeAware(false);
return spf.newSAXParser().getXMLReader();
}
public static DocumentBuilder documentBuilder() throws
ParserConfigurationException {
- DocumentBuilderFactory dbf = DOCUMENT_BUILDER_FACTORY.get();
- if (dbf == null) {
- dbf = DocumentBuilderFactory.newInstance();
- dbf.setNamespaceAware(true);
- dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
Boolean.TRUE);
-
dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl", true);
-
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
-
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities",
false);
-
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
- dbf.setXIncludeAware(false);
- dbf.setExpandEntityReferences(false);
- DOCUMENT_BUILDER_FACTORY.set(dbf);
- }
+ DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
+ dbf.setNamespaceAware(true);
+ dbf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+ dbf.setFeature("http://apache.org/xml/features/disallow-doctype-decl",
true);
+
dbf.setFeature("http://xml.org/sax/features/external-general-entities", false);
+
dbf.setFeature("http://xml.org/sax/features/external-parameter-entities",
false);
+
dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd",
false);
+ dbf.setXIncludeAware(false);
+ dbf.setExpandEntityReferences(false);
return dbf.newDocumentBuilder();
}
public static Transformer transformer() throws
TransformerConfigurationException {
- TransformerFactory tf = TRANSFORMER_FACTORY.get();
- if (tf == null) {
- tf = TransformerFactory.newInstance();
- tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
Boolean.TRUE);
- try {
- tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
- } catch (IllegalArgumentException e) {
- LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_DTD);
- }
- try {
- tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
- } catch (IllegalArgumentException e) {
- LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
- }
- TRANSFORMER_FACTORY.set(tf);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+ try {
+ tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_DTD);
+ }
+ try {
+ tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
}
return tf.newTransformer();
}
private static Transformer transformer(Source xsltSource) throws
TransformerConfigurationException {
- TransformerFactory tf = TRANSFORMER_FACTORY.get();
- if (tf == null) {
- tf = TransformerFactory.newInstance();
- tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING,
Boolean.TRUE);
- try {
- tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
- } catch (IllegalArgumentException e) {
- LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_DTD);
- }
- try {
- tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
- } catch (IllegalArgumentException e) {
- LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
- }
- TRANSFORMER_FACTORY.set(tf);
+ TransformerFactory tf = TransformerFactory.newInstance();
+ tf.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, Boolean.TRUE);
+ try {
+ tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_DTD, "");
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_DTD);
+ }
+ try {
+ tf.setAttribute(XMLConstants.ACCESS_EXTERNAL_STYLESHEET, "");
+ } catch (IllegalArgumentException e) {
+ LOGGER.warn("XSL transformer implementation doesn't support {}
feature", XMLConstants.ACCESS_EXTERNAL_STYLESHEET);
}
return tf.newTransformer(xsltSource);
}