This is an automated email from the ASF dual-hosted git repository.
jerryshao pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/gravitino.git
The following commit(s) were added to refs/heads/main by this push:
new 761c106bdb [#13403] fix(core): quote replacement values in
JobManager.replacePlaceholder (#13404)
761c106bdb is described below
commit 761c106bdbf4846fe91794560ef54bc7d9a1d5d0
Author: YangJie <[email protected]>
AuthorDate: Tue Sep 22 05:12:18 2026 -0400
[#13403] fix(core): quote replacement values in
JobManager.replacePlaceholder (#13404)
### What changes were proposed in this pull request?
`JobManager.replacePlaceholder` now passes replacement values through
`Matcher.quoteReplacement`, so substitution is literal. The no-match
fallback keeps the original placeholder text as before.
### Why are the changes needed?
`Matcher.appendReplacement` interprets `$` and `\` in the replacement as
group references and escapes, so a value like `cost=$5` threw
`IndexOutOfBoundsException` and `p$1x` substituted the wrong text.
Placeholders are documented as literal substitution.
Fix: #13403
### Does this PR introduce _any_ user-facing change?
No.
### How was this patch tested?
Added `TestJobTemplate.testReplacePlaceholdersWithSpecialCharacters`,
covering values with `$5`, `p$1x`, and a backslash. It fails against the
pre-fix code.
---
.../main/java/org/apache/gravitino/job/JobManager.java | 2 +-
.../java/org/apache/gravitino/job/TestJobTemplate.java | 16 ++++++++++++++++
2 files changed, 17 insertions(+), 1 deletion(-)
diff --git a/core/src/main/java/org/apache/gravitino/job/JobManager.java
b/core/src/main/java/org/apache/gravitino/job/JobManager.java
index 6fef520af7..56614b15ba 100644
--- a/core/src/main/java/org/apache/gravitino/job/JobManager.java
+++ b/core/src/main/java/org/apache/gravitino/job/JobManager.java
@@ -957,7 +957,7 @@ public class JobManager implements JobOperationDispatcher {
String key = matcher.group(1);
String replacement = replacements.get(key);
if (replacement != null) {
- matcher.appendReplacement(result, replacement);
+ matcher.appendReplacement(result,
Matcher.quoteReplacement(replacement));
} else {
// If no replacement is found, keep the placeholder as is
matcher.appendReplacement(result, matcher.group(0));
diff --git a/core/src/test/java/org/apache/gravitino/job/TestJobTemplate.java
b/core/src/test/java/org/apache/gravitino/job/TestJobTemplate.java
index 3ce6d1b87c..7d2115d8c3 100644
--- a/core/src/test/java/org/apache/gravitino/job/TestJobTemplate.java
+++ b/core/src/test/java/org/apache/gravitino/job/TestJobTemplate.java
@@ -141,6 +141,22 @@ public class TestJobTemplate {
Assertions.assertEquals("Hello, Hank! Your score is 300.", result);
}
+ @Test
+ public void testReplacePlaceholdersWithSpecialCharacters() {
+ // Replacement values containing '$' and '\' must be treated as literal
text,
+ // not as Matcher replacement syntax (group references and escapes).
+ String template = "config={{conf}}";
+
+ Map<String, String> replacements = ImmutableMap.of("conf", "path=C:\\tmp
and cost=$5");
+ String result = JobManager.replacePlaceholder(template, replacements);
+ Assertions.assertEquals("config=path=C:\\tmp and cost=$5", result);
+
+ // A '$' followed by a digit must not substitute the placeholder's own
group
+ replacements = ImmutableMap.of("conf", "p$1x");
+ result = JobManager.replacePlaceholder(template, replacements);
+ Assertions.assertEquals("config=p$1x", result);
+ }
+
@Test
public void testFetchFilesFromUir() throws IOException {
File testFile1 = Files.createTempFile(tempDir.toPath(), "testFile1",
".txt").toFile();