Skip to content

Commit af29a79

Browse files
sunyuhan1998markpollack
authored andcommitted
Added a "skipBuiltInFunctionsValidation" option to StTemplateRenderer, which defaults to false. When enabled, it skips validation of built-in functions in the template, preventing these built-in functions from being validated as variables to be replaced.
Signed-off-by: Sun Yuhan <1085481446@qq.com>
1 parent b39805a commit af29a79

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

spring-ai-template-st/src/main/java/org/springframework/ai/template/st/StTemplateRenderer.java

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.springframework.ai.template.ValidationMode;
2525
import org.springframework.util.Assert;
2626
import org.stringtemplate.v4.ST;
27+
import org.stringtemplate.v4.compiler.Compiler;
2728
import org.stringtemplate.v4.compiler.STLexer;
2829

2930
import java.util.HashSet;
@@ -48,17 +49,22 @@ public class StTemplateRenderer implements TemplateRenderer {
4849

4950
private static final ValidationMode DEFAULT_VALIDATION_MODE = ValidationMode.THROW;
5051

52+
private static final boolean DEFAULT_SKIP_BUILT_IN_FUNCTIONS_VALIDATION = false;
53+
5154
private final char startDelimiterToken;
5255

5356
private final char endDelimiterToken;
5457

5558
private final ValidationMode validationMode;
5659

57-
StTemplateRenderer(char startDelimiterToken, char endDelimiterToken, ValidationMode validationMode) {
60+
private final boolean skipBuiltInFunctionsValidation;
61+
62+
StTemplateRenderer(char startDelimiterToken, char endDelimiterToken, ValidationMode validationMode, boolean skipBuiltInFunctionsValidation) {
5863
Assert.notNull(validationMode, "validationMode cannot be null");
5964
this.startDelimiterToken = startDelimiterToken;
6065
this.endDelimiterToken = endDelimiterToken;
6166
this.validationMode = validationMode;
67+
this.skipBuiltInFunctionsValidation = skipBuiltInFunctionsValidation;
6268
}
6369

6470
@Override
@@ -113,15 +119,20 @@ private Set<String> getInputVariables(ST st) {
113119
if (token.getType() == STLexer.LDELIM && i + 1 < tokens.size()
114120
&& tokens.get(i + 1).getType() == STLexer.ID) {
115121
if (i + 2 < tokens.size() && tokens.get(i + 2).getType() == STLexer.COLON) {
116-
inputVariables.add(tokens.get(i + 1).getText());
117-
isInsideList = true;
122+
String text = tokens.get(i + 1).getText();
123+
if (!Compiler.funcs.containsKey(text) || !skipBuiltInFunctionsValidation) {
124+
inputVariables.add(text);
125+
isInsideList = true;
126+
}
118127
}
119128
}
120129
else if (token.getType() == STLexer.RDELIM) {
121130
isInsideList = false;
122131
}
123132
else if (!isInsideList && token.getType() == STLexer.ID) {
124-
inputVariables.add(token.getText());
133+
if (!Compiler.funcs.containsKey(token.getText()) || !skipBuiltInFunctionsValidation) {
134+
inputVariables.add(token.getText());
135+
}
125136
}
126137
}
127138

@@ -140,6 +151,8 @@ public static class Builder {
140151

141152
private ValidationMode validationMode = DEFAULT_VALIDATION_MODE;
142153

154+
private boolean skipBuiltInFunctionsValidation = DEFAULT_SKIP_BUILT_IN_FUNCTIONS_VALIDATION;
155+
143156
private Builder() {
144157
}
145158

@@ -158,10 +171,15 @@ public Builder validationMode(ValidationMode validationMode) {
158171
return this;
159172
}
160173

174+
public Builder skipBuiltInFunctionsValidation() {
175+
this.skipBuiltInFunctionsValidation = true;
176+
return this;
177+
}
178+
161179
public StTemplateRenderer build() {
162-
return new StTemplateRenderer(startDelimiterToken, endDelimiterToken, validationMode);
180+
return new StTemplateRenderer(startDelimiterToken, endDelimiterToken, validationMode, skipBuiltInFunctionsValidation);
163181
}
164182

165183
}
166184

167-
}
185+
}

spring-ai-template-st/src/test/java/org/springframework/ai/template/st/StTemplateRendererTests.java

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -280,4 +280,20 @@ void shouldHandleObjectVariables() {
280280
assertThat(result).isEqualTo("Person: John, Age: 30");
281281
}
282282

283-
}
283+
/**
284+
* Test whether StringTemplate can correctly render a template containing built-in functions
285+
* when {@code skipBuiltInFunctionsValidation()} is enabled. It should render properly.
286+
*/
287+
@Test
288+
void shouldRenderTemplateWithSkipBuiltInFunctionsValidation() {
289+
StTemplateRenderer renderer = StTemplateRenderer.builder().skipBuiltInFunctionsValidation().build();
290+
Map<String, Object> variables = new HashMap<>();
291+
variables.put("memory", "you are a helpful assistant");
292+
String template = "{if(strlen(memory))}Hello!{endif}";
293+
294+
String result = renderer.apply(template, variables);
295+
296+
assertThat(result).isEqualTo("Hello!");
297+
}
298+
299+
}

0 commit comments

Comments
 (0)