This is an automated email from the ASF dual-hosted git repository.
Croway pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new b6355fb3d5d6 perf: camel-joor - default-value patterns must not span
two calls on a line
b6355fb3d5d6 is described below
commit b6355fb3d5d679c9e3ddc3e739b62f03d7152d1c
Author: croway <[email protected]>
AuthorDate: Thu Sep 10 21:46:41 2026 +0200
perf: camel-joor - default-value patterns must not span two calls on a line
The headerAs/exchangePropertyAs default-value regexes used a greedy (.+)
for the default value, so with two calls on one line the match ran from
the first call's name to the last call's type. For example
'order-' + headerAs('amount', Integer) + '-' + headerAs('vip', Boolean)
was rewritten to headerAs(message, "amount", Integer) + "-" +
headerAs(message, "vip", Boolean.class) and failed to compile with
"cannot find symbol: variable Integer". The patterns also left the dot of
".class" unescaped and accepted a literal | as a quote via ['|"].
The default value is now matched lazily and may not contain parentheses
except one balanced level (new Date(), '(none)'), so it can never run
into a following call; the type suffix is \.class and quotes are ['"].
The pattern pieces are shared constants so the eight patterns stay in
sync. New tests cover two two-argument calls, two three-argument calls,
mixed forms, .class and no-.class forms, and defaults with parentheses,
for both headerAs and exchangePropertyAs; all three fail on the old
patterns.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
(cherry picked from commit ae61f2b5d3f86857132742227350d711a49ede16)
---
.../apache/camel/language/joor/JoorCompiler.java | 26 ++++++++++-----
.../camel/language/joor/JoorLanguageTest.java | 38 ++++++++++++++++++++++
2 files changed, 55 insertions(+), 9 deletions(-)
diff --git
a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorCompiler.java
b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorCompiler.java
index dbdf37e4aa79..4a9513bb0193 100644
---
a/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorCompiler.java
+++
b/components/camel-joor/src/main/java/org/apache/camel/language/joor/JoorCompiler.java
@@ -38,29 +38,37 @@ import org.slf4j.LoggerFactory;
public class JoorCompiler extends ServiceSupport implements StaticService {
+ // quoted name: 'foo' or "foo"
+ private static final String QUOTED_NAME = "(['\"][A-Za-z0-9.$]*['\"])";
+ // default value: anything but parentheses, or a single level of balanced
parentheses (eg new Date(), '(none)'),
+ // so a default value can never span from one headerAs/exchangePropertyAs
call into the next one on the same line
+ private static final String DEFAULT_VALUE = "((?:[^()]|\\([^()]*\\))+?)";
+ private static final String TYPE_CLASS = "([A-Za-z0-9.$]*\\.class)";
+ private static final String TYPE_NO_CLASS = "([A-Za-z0-9.$]*)";
+
private static final Pattern BEAN_INJECTION_PATTERN =
Pattern.compile("(#bean:)([A-Za-z0-9-_]*)");
- private static final Pattern BODY_AS_PATTERN =
Pattern.compile("(optionalBodyAs|bodyAs)\\(([A-Za-z0-9.$]*)(.class)\\)");
+ private static final Pattern BODY_AS_PATTERN =
Pattern.compile("(optionalBodyAs|bodyAs)\\(([A-Za-z0-9.$]*)(\\.class)\\)");
private static final Pattern BODY_AS_PATTERN_NO_CLASS =
Pattern.compile("(optionalBodyAs|bodyAs)\\(([A-Za-z0-9.$]*)\\)");
private static final Pattern HEADER_AS_PATTERN
- =
Pattern.compile("(optionalHeaderAs|headerAs)\\((['|\"][A-Za-z0-9.$]*['|\"]\\s*),\\s*([A-Za-z0-9.$]*.class)\\)");
+ = Pattern.compile("(optionalHeaderAs|headerAs)\\(" + QUOTED_NAME +
"\\s*,\\s*" + TYPE_CLASS + "\\)");
private static final Pattern HEADER_AS_PATTERN_NO_CLASS
- =
Pattern.compile("(optionalHeaderAs|headerAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,\\s*([A-Za-z0-9.$]*)\\)");
+ = Pattern.compile("(optionalHeaderAs|headerAs)\\(" + QUOTED_NAME +
"\\s*,\\s*" + TYPE_NO_CLASS + "\\)");
private static final Pattern HEADER_AS_DEFAULT_VALUE_PATTERN
- =
Pattern.compile("(headerAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,(.+),\\s*([A-Za-z0-9.$]*.class)\\)");
+ = Pattern.compile("(headerAs)\\(" + QUOTED_NAME + "\\s*," +
DEFAULT_VALUE + ",\\s*" + TYPE_CLASS + "\\)");
private static final Pattern HEADER_AS_DEFAULT_VALUE_PATTERN_NO_CLASS
- =
Pattern.compile("(headerAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,(.+),\\s*([A-Za-z0-9.$]*)\\)");
+ = Pattern.compile("(headerAs)\\(" + QUOTED_NAME + "\\s*," +
DEFAULT_VALUE + ",\\s*" + TYPE_NO_CLASS + "\\)");
private static final Pattern EXCHANGE_PROPERTY_AS_PATTERN
= Pattern.compile(
-
"(optionalExchangePropertyAs|exchangePropertyAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,\\s*([A-Za-z0-9.$]*.class)\\)");
+ "(optionalExchangePropertyAs|exchangePropertyAs)\\(" +
QUOTED_NAME + "\\s*,\\s*" + TYPE_CLASS + "\\)");
private static final Pattern EXCHANGE_PROPERTY_AS_PATTERN_NO_CLASS
= Pattern.compile(
-
"(optionalExchangePropertyAs|exchangePropertyAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,\\s*([A-Za-z0-9.$]*)\\)");
+ "(optionalExchangePropertyAs|exchangePropertyAs)\\(" +
QUOTED_NAME + "\\s*,\\s*" + TYPE_NO_CLASS + "\\)");
private static final Pattern EXCHANGE_PROPERTY_AS_DEFAULT_VALUE_PATTERN
= Pattern.compile(
-
"(exchangePropertyAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,(.+),\\s*([A-Za-z0-9.$]*.class)\\)");
+ "(exchangePropertyAs)\\(" + QUOTED_NAME + "\\s*," +
DEFAULT_VALUE + ",\\s*" + TYPE_CLASS + "\\)");
private static final Pattern
EXCHANGE_PROPERTY_AS_DEFAULT_VALUE_PATTERN_NO_CLASS
= Pattern.compile(
-
"(exchangePropertyAs)\\((['|\"][A-Za-z0-9.$]*['|\"])\\s*,(.+),\\s*([A-Za-z0-9.$]*)\\)");
+ "(exchangePropertyAs)\\(" + QUOTED_NAME + "\\s*," +
DEFAULT_VALUE + ",\\s*" + TYPE_NO_CLASS + "\\)");
private static final Logger LOG =
LoggerFactory.getLogger(JoorCompiler.class);
private static final AtomicInteger UUID = new AtomicInteger();
diff --git
a/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorLanguageTest.java
b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorLanguageTest.java
index c1807a79339e..cbf08d8c6b74 100644
---
a/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorLanguageTest.java
+++
b/components/camel-joor/src/test/java/org/apache/camel/language/joor/JoorLanguageTest.java
@@ -158,6 +158,34 @@ public class JoorLanguageTest extends LanguageTestSupport {
assertExpression("'Hello ' + headerAs('dog', 'World', String)", "Hello
World");
}
+ @Test
+ public void testExchangeHeaderAsTwoCallsInOneExpression() {
+ exchange.getIn().setHeader("amount", 42);
+ exchange.getIn().setHeader("vip", true);
+
+ assertExpression("'order-' + headerAs('amount', Integer) + '-' +
headerAs('vip', Boolean)", "order-42-true");
+ assertExpression("'order-' + headerAs('amount', Integer.class) + '-' +
headerAs('vip', Boolean.class)",
+ "order-42-true");
+ assertExpression("'order-' + headerAs('amount', int) + '-' +
headerAs('vip', Boolean.class)", "order-42-true");
+ assertExpression("headerAs('amount', Integer) + headerAs('amount',
Integer)", "84");
+ }
+
+ @Test
+ public void testExchangeHeaderAsDefaultValueTwoCallsInOneExpression() {
+ exchange.getIn().setHeader("a", 40);
+
+ assertExpression("headerAs('a', 1, Integer) + headerAs('b', 2,
Integer)", "42");
+ assertExpression("headerAs('a', 1, Integer.class) + headerAs('b', 2,
Integer.class)", "42");
+ assertExpression("headerAs('a', 1, Integer) + headerAs('b', 2,
Integer.class)", "42");
+ assertExpression("headerAs('a', 1, Integer.class) + headerAs('b', 2,
Integer)", "42");
+ // two-argument and three-argument forms mixed on the same line
+ assertExpression("headerAs('a', Integer) + headerAs('b', 2, Integer)",
"42");
+ assertExpression("headerAs('b', 2, Integer) + headerAs('a', Integer)",
"42");
+ // default values containing parentheses and quotes
+ assertExpression("headerAs('x', '(none)', String) + headerAs('y',
\"(n/a)\", String)", "(none)(n/a)");
+ assertExpression("headerAs('b', Integer.valueOf(2), Integer) +
headerAs('a', Integer)", "42");
+ }
+
@Test
public void testExchangeOptionalHeaderAs() {
exchange.getIn().setHeader("foo", 22);
@@ -179,6 +207,16 @@ public class JoorLanguageTest extends LanguageTestSupport {
assertExpression("var num = optionalHeaderAs(\"foo\", int).get();
return num * 4", "88");
}
+ @Test
+ public void testExchangePropertyAsTwoCallsInOneExpression() {
+ exchange.setProperty("a", 40);
+
+ assertExpression("exchangePropertyAs('a', Integer) +
exchangePropertyAs('a', Integer.class)", "80");
+ assertExpression("exchangePropertyAs('a', 1, Integer) +
exchangePropertyAs('b', 2, Integer)", "42");
+ assertExpression("exchangePropertyAs('a', 1, Integer.class) +
exchangePropertyAs('b', 2, Integer.class)", "42");
+ assertExpression("exchangePropertyAs('a', Integer) +
exchangePropertyAs('b', 2, Integer)", "42");
+ }
+
@Test
public void testExchangePropertyAs() {
exchange.setProperty("bar", 22);