This is an automated email from the ASF dual-hosted git repository.

henrib pushed a commit to branch JEXL-455
in repository https://gitbox.apache.org/repos/asf/commons-jexl.git

commit 36dc64dfb9195a97bba67c99d7bf863140dc539f
Author: Henrib <[email protected]>
AuthorDate: Wed Feb 4 12:35:38 2026 +0100

    JEXL-455: ignore whitespaces when creating embedded expressions 
(interpolations, templates);
---
 .../commons/jexl3/internal/TemplateEngine.java     | 95 ++++++++++++----------
 .../org/apache/commons/jexl3/Issues400Test.java    | 33 ++++++++
 2 files changed, 83 insertions(+), 45 deletions(-)

diff --git 
a/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java 
b/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
index 75b66e11..b4be891d 100644
--- a/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
+++ b/src/main/java/org/apache/commons/jexl3/internal/TemplateEngine.java
@@ -1073,7 +1073,7 @@ public final class TemplateEngine extends JxltEngine {
                         strb.delete(0, Integer.MAX_VALUE);
                         state = ParseState.CONST;
                     }
-                } else {
+                } else if (!isIgnorable(c)) {
                     if (c == '{') {
                         immediate1 += 1;
                     }
@@ -1086,54 +1086,54 @@ public final class TemplateEngine extends JxltEngine {
                 // nested immediate in deferred; need to balance count of '{' 
& '}'
                 // closing '}'
                 switch (c) {
-                case '"':
-                case '\'':
-                    strb.append(c);
-                    column = StringParser.readString(strb, expr, column + 1, 
c);
-                    continue;
-                case '{':
-                    if (expr.charAt(column - 1) == immediateChar) {
-                        inner1 += 1;
-                        strb.deleteCharAt(strb.length() - 1);
-                        nested = true;
-                    } else {
-                        deferred1 += 1;
-                        strb.append(c);
-                    }
-                    continue;
-                case '}':
-                    // balance nested immediate
-                    if (deferred1 > 0) {
-                        deferred1 -= 1;
+                    case '"':
+                    case '\'':
                         strb.append(c);
-                    } else if (inner1 > 0) {
-                        inner1 -= 1;
-                    } else {
-                        // materialize the nested/deferred expr
-                        final String src = escapeString(strb);
-                        final JexlInfo srcInfo = info.at(lineno, column);
-                        TemplateExpression dexpr;
-                        if (nested) {
-                            dexpr = new NestedExpression(
-                                        escapeString(expr.substring(inested, 
column + 1)),
+                        column = StringParser.readString(strb, expr, column + 
1, c);
+                        continue;
+                    case '{':
+                        if (expr.charAt(column - 1) == immediateChar) {
+                            inner1 += 1;
+                            strb.deleteCharAt(strb.length() - 1);
+                            nested = true;
+                        } else {
+                            deferred1 += 1;
+                            strb.append(c);
+                        }
+                        continue;
+                    case '}':
+                        // balance nested immediate
+                        if (deferred1 > 0) {
+                            deferred1 -= 1;
+                            strb.append(c);
+                        } else if (inner1 > 0) {
+                            inner1 -= 1;
+                        } else if (!isIgnorable(c)) {
+                            // materialize the nested/deferred expr
+                            final String src = escapeString(strb);
+                            final JexlInfo srcInfo = info.at(lineno, column);
+                            TemplateExpression dexpr;
+                            if (nested) {
+                                dexpr = new NestedExpression(
+                                            
escapeString(expr.substring(inested, column + 1)),
+                                            jexl.jxltParse(srcInfo, noscript, 
src, scope),
+                                     null);
+                            } else {
+                                dexpr = new DeferredExpression(
+                                        src,
                                         jexl.jxltParse(srcInfo, noscript, src, 
scope),
                                  null);
-                        } else {
-                            dexpr = new DeferredExpression(
-                                    src,
-                                    jexl.jxltParse(srcInfo, noscript, src, 
scope),
-                             null);
+                            }
+                            builder.add(dexpr);
+                            strb.delete(0, Integer.MAX_VALUE);
+                            nested = false;
+                            state = ParseState.CONST;
                         }
-                        builder.add(dexpr);
-                        strb.delete(0, Integer.MAX_VALUE);
-                        nested = false;
-                        state = ParseState.CONST;
-                    }
-                    break;
-                default:
-                    // do buildup expr
-                    column = append(strb, expr, column, c);
-                    break;
+                        break;
+                    default:
+                        // do buildup expr
+                        column = append(strb, expr, column, c);
+                        break;
                 }
                 break;
             case ESCAPE:
@@ -1184,6 +1184,11 @@ public final class TemplateEngine extends JxltEngine {
         return StringParser.escapeString(str, (char) 0);
     }
 
+    private static boolean isIgnorable(char c) {
+        return c == '\n' || c == '\r' || c == '\t' || c == '\f' || c == '\b';
+    }
+
+
     /**
      * Reads lines of a template grouping them by typed blocks.
      *
diff --git a/src/test/java/org/apache/commons/jexl3/Issues400Test.java 
b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
index 2deb4ab9..28b252e8 100644
--- a/src/test/java/org/apache/commons/jexl3/Issues400Test.java
+++ b/src/test/java/org/apache/commons/jexl3/Issues400Test.java
@@ -30,6 +30,7 @@ import static org.junit.jupiter.api.Assertions.fail;
 
 import java.io.Closeable;
 import java.io.File;
+import java.io.StringWriter;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
 import java.util.Arrays;
@@ -798,6 +799,38 @@ public class Issues400Test {
         Assertions.assertEquals(ctl, o);
     }
 
+    @Test
+    void testIssue455a() {
+        final JexlEngine jexl = new JexlBuilder().create();
+        String code = "name -> `${name +\n name}`";
+        JexlScript script = jexl.createScript(code);
+        Object o = script.execute(null, "Hello");
+        String ctl = "HelloHello";
+        Assertions.assertEquals(ctl, o);
+    }
+
+    @Test
+    void testIssue455b() {
+        final JexlEngine jexl = new JexlBuilder().create();
+        String code = "name -> `${name}\n${name}`;";
+        JexlScript script = jexl.createScript(code);
+        Object o = script.execute(null, "Hello");
+        String ctl = "Hello\nHello";
+        Assertions.assertEquals(ctl, o);
+    }
+
+    @Test
+    void testIssue455() {
+        final JexlEngine jexl = new JexlBuilder().create();
+        final JexlContext context = new MapContext();
+        context.set("name", "Hello");
+        final JxltEngine jxlt = jexl.createJxltEngine();
+        final JxltEngine.Template template = 
jxlt.createTemplate("<b>\n\t${name\n\t+ name}\n</b>");
+        final StringWriter writer = new StringWriter();
+        template.evaluate(context, writer);
+        assertEquals("<b>\n\tHelloHello\n</b>", writer.toString());
+    }
+
     @Test
     void testIssue442() {
         final JexlEngine jexl = new JexlBuilder().create();

Reply via email to