Skip to content

Commit 3d54cc3

Browse files
authored
Add leniency to missing array values in mustache (#126550)
In mustache, this change returns null values which convert to empty strings instead of throwing an exception when users have a template with something like a.8 where the index 8 is out of bounds. This matches the behavior for non-existent keys like a.d. Closes #55200
1 parent 31e5678 commit 3d54cc3

File tree

3 files changed

+30
-4
lines changed

3 files changed

+30
-4
lines changed

docs/changelog/126550.yaml

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 126550
2+
summary: Add leniency to missing array values in mustache
3+
area: Infra/Scripting
4+
type: bug
5+
issues:
6+
- 55200

modules/lang-mustache/src/main/java/org/elasticsearch/script/mustache/CustomReflectionObjectHandler.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,11 @@ public Object get(Object key) {
111111
if ("size".equals(key)) {
112112
return size();
113113
} else if (key instanceof Number number) {
114-
return Array.get(array, number.intValue());
114+
return number.intValue() >= 0 && number.intValue() < length ? Array.get(array, number.intValue()) : null;
115115
}
116116
try {
117117
int index = Integer.parseInt(key.toString());
118-
return Array.get(array, index);
118+
return index >= 0 && index < length ? Array.get(array, index) : null;
119119
} catch (NumberFormatException nfe) {
120120
// if it's not a number it is as if the key doesn't exist
121121
return null;
@@ -169,11 +169,11 @@ public Object get(Object key) {
169169
if ("size".equals(key)) {
170170
return col.size();
171171
} else if (key instanceof Number number) {
172-
return Iterables.get(col, number.intValue());
172+
return number.intValue() >= 0 && number.intValue() < col.size() ? Iterables.get(col, number.intValue()) : null;
173173
}
174174
try {
175175
int index = Integer.parseInt(key.toString());
176-
return Iterables.get(col, index);
176+
return index >= 0 && index < col.size() ? Iterables.get(col, index) : null;
177177
} catch (NumberFormatException nfe) {
178178
// if it's not a number it is as if the key doesn't exist
179179
return null;

modules/lang-mustache/src/test/java/org/elasticsearch/script/mustache/MustacheTests.java

+20
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,26 @@ public void testMapInArrayAccess() throws Exception {
141141
assertThat(output, both(containsString("foo")).and(containsString("bar")));
142142
}
143143

144+
public void testMapInArrayBadAccess() throws Exception {
145+
String template = "{{data.0.key}} {{data.2.key}}";
146+
TemplateScript.Factory factory = engine.compile(null, template, TemplateScript.CONTEXT, Collections.emptyMap());
147+
Map<String, Object> vars = new HashMap<>();
148+
vars.put("data", new Object[] { singletonMap("key", "foo"), singletonMap("key", "bar") });
149+
// assertThat(factory.newInstance(vars).execute(), equalTo("foo "));
150+
151+
vars.put("data", Arrays.asList(singletonMap("key", "foo"), singletonMap("key", "bar")));
152+
factory.newInstance(vars);
153+
assertThat(factory.newInstance(vars).execute(), equalTo("foo "));
154+
155+
// HashSet iteration order isn't fixed
156+
Set<Object> setData = new HashSet<>();
157+
setData.add(singletonMap("key", "foo"));
158+
setData.add(singletonMap("key", "bar"));
159+
vars.put("data", setData);
160+
String output = factory.newInstance(vars).execute();
161+
assertThat(output, both(containsString("foo")).and(not(containsString("bar"))));
162+
}
163+
144164
public void testSizeAccessForCollectionsAndArrays() throws Exception {
145165
String[] randomArrayValues = generateRandomStringArray(10, 20, false);
146166
List<String> randomList = Arrays.asList(generateRandomStringArray(10, 20, false));

0 commit comments

Comments
 (0)