This is an automated email from the ASF dual-hosted git repository.
yesamer pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie.git
The following commit(s) were added to refs/heads/main by this push:
new a68b7c1b126 performance(kie-dmn-feel): Performance regression in
Drools v10+ with DMN models (#6871)
a68b7c1b126 is described below
commit a68b7c1b126b1f51bd761dc124c0b17194061a24
Author: Yeser Amer <[email protected]>
AuthorDate: Fri Aug 7 12:55:41 2026 +0200
performance(kie-dmn-feel): Performance regression in Drools v10+ with DMN
models (#6871)
* Improve replace and matches functions performances
* Additional improvements
* Doc changes
* MInor
* Minor
* Tests added.
* minor
* Change Request
---
.../java/org/kie/dmn/feel/util/XQueryImplUtil.java | 57 +++++++++++++++-------
.../org/kie/dmn/feel/util/XQueryImplUtilTest.java | 40 +++++++++++++++
kie-parent/pom.xml | 2 +-
3 files changed, 80 insertions(+), 19 deletions(-)
diff --git
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
index e617ae77c1a..f8d28507f18 100644
---
a/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
+++
b/kie-dmn/kie-dmn-feel/src/main/java/org/kie/dmn/feel/util/XQueryImplUtil.java
@@ -26,11 +26,18 @@ import net.sf.saxon.s9api.XQueryEvaluator;
import net.sf.saxon.s9api.XQueryExecutable;
import net.sf.saxon.s9api.SaxonApiException;
-import java.util.regex.Pattern;
-
public class XQueryImplUtil {
- private static final Pattern XML_CHARACTER_REFERENCES_PATTERN =
Pattern.compile("['\"&<>]");
+ /** Shared across all calls. Thread-safe; expensive to construct. One
instance per JVM is sufficient.
+ * See Saxon s9api {@link net.sf.saxon.s9api.Processor} Javadoc. */
+ private static final Processor PROCESSOR = new Processor(false);
+
+ /**
+ * Shared across all calls. Concurrent use is permitted, but error
messages may not be
+ * attributed to the correct thread under concurrent error conditions.
+ * See Saxon s9api {@link net.sf.saxon.s9api.XQueryCompiler} Javadoc.
+ */
+ private static final XQueryCompiler COMPILER =
PROCESSOR.newXQueryCompiler();
private XQueryImplUtil() {
// Util class with static methods only.
@@ -50,9 +57,7 @@ public class XQueryImplUtil {
static <T> T evaluateXQueryExpression(String expression, Class<T>
expectedTypeResult) {
try {
- Processor processor = new Processor(false);
- XQueryCompiler compiler = processor.newXQueryCompiler();
- XQueryExecutable executable = compiler.compile(expression);
+ XQueryExecutable executable = COMPILER.compile(expression);
XQueryEvaluator queryEvaluator = executable.load();
XdmItem resultItem = queryEvaluator.evaluateSingle();
@@ -66,22 +71,38 @@ public class XQueryImplUtil {
} catch (SaxonApiException e) {
throw new IllegalArgumentException(e);
}
- }
+ }
/**
- * It replaces all the XML Character References (&, ", ', <, >) in a given
input string with their "escaping" characters.
- * This is required to run XPath functions containing XML Character
References.
- * @param input A string input representing one of the parameter of
managed functions
- * @return A sanitized string
+ * Escapes XML special characters ({@code & " ' < >}) so the value is safe
to embed
+ * as an XPath string literal. Returns {@code null} unchanged; returns the
original
+ * reference if no escaping is needed.
*/
static String escapeXmlCharactersReferencesForXPath(String input) {
- if (input != null &&
XML_CHARACTER_REFERENCES_PATTERN.matcher(input).find()) {
- input = input.contains("&") ? input.replace("&", "&") : input;
- input = input.contains("\"") ? input.replace("\"", """) :
input;
- input = input.contains("'") ? input.replace("'", "'") :
input;
- input = input.contains("<") ? input.replace("<", "<") : input;
- input = input.contains(">") ? input.replace(">", ">") : input;
+ if (input == null) {
+ return null;
+ }
+ StringBuilder sb = null;
+ for (int i = 0; i < input.length(); i++) {
+ char ch = input.charAt(i);
+ String replacement = switch (ch) {
+ case '&' -> "&";
+ case '"' -> """;
+ case '\'' -> "'";
+ case '<' -> "<";
+ case '>' -> ">";
+ default -> null;
+ };
+ if (replacement != null) {
+ if (sb == null) {
+ sb = new StringBuilder(input.length() + 16);
+ sb.append(input, 0, i);
+ }
+ sb.append(replacement);
+ } else if (sb != null) {
+ sb.append(ch);
+ }
}
- return input;
+ return sb != null ? sb.toString() : input;
}
}
diff --git
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
index c196d33588a..c968a7da262 100644
---
a/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
+++
b/kie-dmn/kie-dmn-feel/src/test/java/org/kie/dmn/feel/util/XQueryImplUtilTest.java
@@ -37,6 +37,18 @@ class XQueryImplUtilTest {
{ "test", "^test", "i", true },
{ "fo\nbar", "o.b", null, false },
{ "TEST", "test", "i", true },
+ // flags
+ { "test", "^test", "", true }, //
flags = "" explicitly
+ { "FO\nBAR", "fo.bar", "si", true }, //
dotall + case-insensitive
+ { "hello\nworld", "^WORLD", "mi", true }, //
multiline + case-insensitive
+ // XML special characters in input — exercises the
escape→embed→evaluate pipeline
+ { "it's", "it.s", "", true }, //
single quote in input
+ { "say \"hi\"", "say .hi.", "", true }, //
double quote in input
+ { "a&b", "a.b", "", true }, //
ampersand in input
+ { "a<b", "a.b", "", true }, //
less-than in input
+ { "a>b", "a.b", "", true }, //
greater-than in input
+ // XML special characters in pattern
+ { "<tag>", "<tag>", "", true }, //
angle brackets in pattern
};
}
@@ -66,6 +78,16 @@ class XQueryImplUtilTest {
return new Object[][] {
{ "testString", "^test", "ttt", "", "tttString" },
{ "fo\nbar", "o.b", "ttt", "s", "ftttar" },
+ // flags
+ { "FO\nBAR", "fo.bar", "X", "si", "X" }, //
dotall + case-insensitive
+ // XML special characters in input — exercises the
escape→embed→evaluate pipeline
+ { "a&b", "a.b", "X", "", "X" }, //
ampersand in input
+ { "it's", "it.s", "X", "", "X" }, //
single quote in input
+ // XML special characters in replacement
+ { "hello", "hello", "a&b", "", "a&b" }, //
ampersand in replacement
+ { "hello", "hello", "it's", "", "it's" }, //
single quote in replacement
+ // backreference in replacement
+ { "hello", "(h)", "$1$1", "", "hhello" }, // $1
backreference
};
}
@@ -122,12 +144,30 @@ class XQueryImplUtilTest {
private static Object[][] escapeXmlCharactersReferencesForXPathTestData() {
return new Object[][] {
+ // null / empty
{ null, null },
{ "", "" },
+ // no special chars — original reference must be returned
unchanged
{ "lolASD", "lolASD" },
+ // each of the five special characters in isolation
(single-char string)
+ { "&", "&" },
+ { "\"", """ },
+ { "'", "'" },
+ { "<", "<" },
+ { ">", ">" },
+ // mixed: < and > (no &, no quotes)
{ "List<String>", "List<String>" },
+ // mixed: " only
{ "\"Mr.Y\"", ""Mr.Y"" },
+ // mixed: all five present — ' < & > ' (missing " in a
multi-char mix)
{ "'<&>'", "'<&>'" },
+ // mixed: all five chars including " alongside others
+ { "a&b\"c'<d>", "a&b"c'<d>" },
+ // special char first, last, and in the middle
+ { "&start", "&start" },
+ { "end&", "end&" },
+ { "mid&dle", "mid&dle" },
+ { "no special chars here 1234", "no special chars here 1234" },
};
}
diff --git a/kie-parent/pom.xml b/kie-parent/pom.xml
index 6fc5792f80b..9c7aa2c2d1f 100644
--- a/kie-parent/pom.xml
+++ b/kie-parent/pom.xml
@@ -205,7 +205,7 @@
<version.net.byte-buddy>1.17.6</version.net.byte-buddy>
<version.net.java.dev.glazedlists>1.8.0</version.net.java.dev.glazedlists>
<version.net.minidev.jsonsmart>2.4.10</version.net.minidev.jsonsmart>
- <version.net.sf.saxon.Saxon-HE>12.7</version.net.sf.saxon.Saxon-HE>
+ <version.net.sf.saxon.Saxon-HE>12.10</version.net.sf.saxon.Saxon-HE>
<version.net.thisptr.jackson-jq>1.0.0-preview.20240207</version.net.thisptr.jackson-jq>
<version.org.antlr>3.5.2</version.org.antlr>
<version.org.antlr.ST4>4.0.7</version.org.antlr.ST4>
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]