Repository: PebbleTemplates/pebble
Pull request #650 (2023-03-24 17:08:47)

Fix the null pointer exception on the replace filter
There is a check missing before doing toString() on the input.

ebussieres: Can you add a unit test for this case please ?

Thank you for your contribution 
fabriceci: Of course, it's done.

Patch:
diff --git a/pebble/src/main/java/io/pebbletemplates/pebble/extension/core/ReplaceFilter.java b/pebble/src/main/java/io/pebbletemplates/pebble/extension/core/ReplaceFilter.java
index f3863563..cdc2a344 100644
--- a/pebble/src/main/java/io/pebbletemplates/pebble/extension/core/ReplaceFilter.java
+++ b/pebble/src/main/java/io/pebbletemplates/pebble/extension/core/ReplaceFilter.java
@@ -32,14 +32,16 @@ public class ReplaceFilter implements Filter {
   @Override
   public Object apply(Object input, Map<String, Object> args, PebbleTemplate self,
                       EvaluationContext context, int lineNumber) throws PebbleException {
-    String data = input.toString();
+    if (input == null) {
+      return null;
+    }
     if (args.get(ARGUMENT_NAME) == null) {
       throw new PebbleException(null,
           MessageFormat.format("The argument ''{0}'' is required.", ARGUMENT_NAME), lineNumber,
           self.getName());
     }
     Map<?, ?> replacePair = (Map<?, ?>) args.get(ARGUMENT_NAME);
-
+    String data = input.toString();
     for (Entry<?, ?> entry : replacePair.entrySet()) {
       data = data.replace(entry.getKey().toString(), entry.getValue().toString());
     }


Test patch:
diff --git a/pebble/src/test/java/io/pebbletemplates/pebble/CoreFiltersTest.java b/pebble/src/test/java/io/pebbletemplates/pebble/CoreFiltersTest.java
index f8e7abcf..f1ab66bd 100644
--- a/pebble/src/test/java/io/pebbletemplates/pebble/CoreFiltersTest.java
+++ b/pebble/src/test/java/io/pebbletemplates/pebble/CoreFiltersTest.java
@@ -12,7 +12,6 @@ import io.pebbletemplates.pebble.error.PebbleException;
 import io.pebbletemplates.pebble.extension.TestingExtension;
 import io.pebbletemplates.pebble.extension.core.*;
 import io.pebbletemplates.pebble.loader.StringLoader;
-import io.pebbletemplates.pebble.extension.core.*;
 import io.pebbletemplates.pebble.template.PebbleTemplate;
 
 import org.junit.jupiter.api.Test;
@@ -30,6 +29,7 @@ import static java.lang.Boolean.TRUE;
 import static java.util.Collections.emptyList;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 
 class CoreFiltersTest {
 
@@ -1309,6 +1309,22 @@ class CoreFiltersTest {
     assertEquals("4", writer.toString());
   }
 
+  /**
+   * Tests {@link ReplaceFilter} if it can handle a null input.
+   */
+  @Test
+  void testReplaceFilterNullInput() throws PebbleException, IOException {
+    PebbleEngine pebble = new PebbleEngine.Builder().loader(new StringLoader())
+            .strictVariables(false).build();
+
+    PebbleTemplate template = pebble
+            .getTemplate(
+                    "{{ null |replace({'%this%': foo, '%that%': \"bar\"}) }}");
+
+    Writer writer = new StringWriter();
+    assertDoesNotThrow(() -> template.evaluate(writer, new HashMap<>()));
+  }
+
   /**
    * Tests {@link ReplaceFilter} if the length filter is working within templates.
    */