16
16
17
17
/** Util class that is responsible for parsing a {@link Node}. */
18
18
public final class NodeParser {
19
- private static XPathFactory xPathFactory = XPathFactory .newInstance ();
19
+ // the XPathFactory is not thread safe so every thread gets its own one. It should not be a
20
+ // problem that we do not call remove() on it as it can be reused even after returning the thread
21
+ // to a ThreadPool.
22
+ private static final ThreadLocal <XPathFactory > xPathFactory =
23
+ ThreadLocal .withInitial (XPathFactory ::newInstance );
20
24
21
25
private NodeParser () {
22
26
// Should not be instantiated as an object
@@ -45,7 +49,7 @@ public static Optional<String> getValueFromExpression(String xPathExpression, No
45
49
46
50
// should be invoked on every method call since: An XPath object is not thread-safe and not
47
51
// reentrant.
48
- final XPath xPath = xPathFactory .newXPath ();
52
+ final XPath xPath = xPathFactory .get (). newXPath ();
49
53
String result = (String ) xPath .evaluate (xPathExpression , sourceNode , XPathConstants .STRING );
50
54
return result .isEmpty () ? Optional .empty () : Optional .of (result );
51
55
} catch (XPathExpressionException | NoSuchElementException e ) {
@@ -80,9 +84,12 @@ public static List<Node> getNodesFromExpression(String xPathExpression, Node sou
80
84
try {
81
85
// should be invoked on every method call since: An XPath object is not thread-safe and not
82
86
// reentrant.
83
- final XPath xPath = XPathFactory .newInstance ().newXPath ();
84
87
final NodeList nodeList =
85
- (NodeList ) xPath .evaluate (xPathExpression , sourceNode , XPathConstants .NODESET );
88
+ (NodeList )
89
+ xPathFactory
90
+ .get ()
91
+ .newXPath ()
92
+ .evaluate (xPathExpression , sourceNode , XPathConstants .NODESET );
86
93
return nodeListToList (nodeList );
87
94
} catch (XPathExpressionException | NoSuchElementException e ) {
88
95
throw new XmlProcessingException (e .getMessage (), e );
@@ -100,8 +107,7 @@ public static List<Node> getNodesFromExpression(String xPathExpression, Node sou
100
107
*/
101
108
public static Optional <Node > getNodeFromExpression (String xPathExpression , Node sourceNode ) {
102
109
try {
103
- final XPathFactory xpathfactory = XPathFactory .newInstance ();
104
- final XPath xpath = xpathfactory .newXPath ();
110
+ final XPath xpath = xPathFactory .get ().newXPath ();
105
111
final var result = xpath .evaluate (xPathExpression , sourceNode , XPathConstants .NODE );
106
112
if (result instanceof Node node ) {
107
113
return Optional .of (node );
0 commit comments