This is an automated email from the ASF dual-hosted git repository.
jbonofre pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/karaf.git
The following commit(s) were added to refs/heads/main by this push:
new 7a3f8f859d Remove static ThreadLocal caching in XmlUtils to prevent
ClassLoader leaks (#2516)
7a3f8f859d is described below
commit 7a3f8f859dc4ef71f660591624b34696cd6ffc1d
Author: JB Onofré <[email protected]>
AuthorDate: Wed Apr 15 18:57:16 2026 +0200
Remove static ThreadLocal caching in XmlUtils to prevent ClassLoader leaks
(#2516)
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);
}