Skip to content

Commit 1f85a8e

Browse files
Michael McCandlessmikemccand
Michael McCandless
authored andcommitted
Source filtering: only accept array items if the previous include pattern matches (#22593)
Source filtering was always accepting array items even if the include pattern did not match. Closes #22557
1 parent 02e08cf commit 1f85a8e

File tree

2 files changed

+44
-34
lines changed

2 files changed

+44
-34
lines changed

core/src/main/java/org/elasticsearch/common/xcontent/support/XContentMapValues.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,7 @@ private static Map<String, Object> filter(Map<String, ?> map,
266266

267267
List<Object> filteredValue = filter((Iterable<?>) value,
268268
subIncludeAutomaton, subIncludeState, excludeAutomaton, excludeState, matchAllAutomaton);
269-
if (includeAutomaton.isAccept(includeState) || filteredValue.isEmpty() == false) {
269+
if (filteredValue.isEmpty() == false) {
270270
filtered.put(key, filteredValue);
271271
}
272272

@@ -289,6 +289,7 @@ private static List<Object> filter(Iterable<?> iterable,
289289
CharacterRunAutomaton excludeAutomaton, int initialExcludeState,
290290
CharacterRunAutomaton matchAllAutomaton) {
291291
List<Object> filtered = new ArrayList<>();
292+
boolean isInclude = includeAutomaton.isAccept(initialIncludeState);
292293
for (Object value : iterable) {
293294
if (value instanceof Map) {
294295
int includeState = includeAutomaton.step(initialIncludeState, '.');
@@ -307,9 +308,8 @@ private static List<Object> filter(Iterable<?> iterable,
307308
if (filteredValue.isEmpty() == false) {
308309
filtered.add(filteredValue);
309310
}
310-
} else {
311-
// TODO: we have tests relying on this behavior on arrays even
312-
// if the path does not match, but this looks like a bug?
311+
} else if (isInclude) {
312+
// #22557: only accept this array value if the key we are on is accepted:
313313
filtered.add(value);
314314
}
315315
}

core/src/test/java/org/elasticsearch/common/xcontent/support/XContentMapValuesTests.java

+40-30
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import static java.util.Collections.singletonMap;
4242
import static org.hamcrest.Matchers.hasEntry;
4343
import static org.hamcrest.Matchers.hasKey;
44+
import static org.hamcrest.Matchers.hasSize;
4445
import static org.hamcrest.Matchers.instanceOf;
4546
import static org.hamcrest.Matchers.nullValue;
4647
import static org.hamcrest.core.IsEqual.equalTo;
@@ -150,8 +151,8 @@ public void testExtractValue() throws Exception {
150151
extValue = XContentMapValues.extractValue("path1.test", map);
151152
assertThat(extValue, instanceOf(List.class));
152153

153-
List extListValue = (List) extValue;
154-
assertThat(extListValue.size(), equalTo(2));
154+
List<?> extListValue = (List) extValue;
155+
assertThat(extListValue, hasSize(2));
155156

156157
builder = XContentFactory.jsonBuilder().startObject()
157158
.startObject("path1")
@@ -170,7 +171,7 @@ public void testExtractValue() throws Exception {
170171
assertThat(extValue, instanceOf(List.class));
171172

172173
extListValue = (List) extValue;
173-
assertThat(extListValue.size(), equalTo(2));
174+
assertThat(extListValue, hasSize(2));
174175
assertThat(extListValue.get(0).toString(), equalTo("value1"));
175176
assertThat(extListValue.get(1).toString(), equalTo("value2"));
176177

@@ -236,9 +237,9 @@ public void testPrefixedNamesFilteringTest() {
236237
Map<String, Object> map = new HashMap<>();
237238
map.put("obj", "value");
238239
map.put("obj_name", "value_name");
239-
Map<String, Object> filterdMap = XContentMapValues.filter(map, new String[]{"obj_name"}, Strings.EMPTY_ARRAY);
240-
assertThat(filterdMap.size(), equalTo(1));
241-
assertThat((String) filterdMap.get("obj_name"), equalTo("value_name"));
240+
Map<String, Object> filteredMap = XContentMapValues.filter(map, new String[]{"obj_name"}, Strings.EMPTY_ARRAY);
241+
assertThat(filteredMap.size(), equalTo(1));
242+
assertThat((String) filteredMap.get("obj_name"), equalTo("value_name"));
242243
}
243244

244245

@@ -253,19 +254,17 @@ public void testNestedFiltering() {
253254
put("nested", 2);
254255
put("nested_2", 3);
255256
}}));
256-
Map<String, Object> falteredMap = XContentMapValues.filter(map, new String[]{"array.nested"}, Strings.EMPTY_ARRAY);
257-
assertThat(falteredMap.size(), equalTo(1));
257+
Map<String, Object> filteredMap = XContentMapValues.filter(map, new String[]{"array.nested"}, Strings.EMPTY_ARRAY);
258+
assertThat(filteredMap.size(), equalTo(1));
258259

259-
// Selecting members of objects within arrays (ex. [ 1, { nested: "value"} ]) always returns all values in the array (1 in the ex)
260-
// this is expected behavior as this types of objects are not supported in ES
261-
assertThat((Integer) ((List) falteredMap.get("array")).get(0), equalTo(1));
262-
assertThat(((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).size(), equalTo(1));
263-
assertThat((Integer) ((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).get("nested"), equalTo(2));
260+
assertThat(((List<?>) filteredMap.get("array")), hasSize(1));
261+
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).size(), equalTo(1));
262+
assertThat((Integer) ((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).get("nested"), equalTo(2));
264263

265-
falteredMap = XContentMapValues.filter(map, new String[]{"array.*"}, Strings.EMPTY_ARRAY);
266-
assertThat(falteredMap.size(), equalTo(1));
267-
assertThat((Integer) ((List) falteredMap.get("array")).get(0), equalTo(1));
268-
assertThat(((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).size(), equalTo(2));
264+
filteredMap = XContentMapValues.filter(map, new String[]{"array.*"}, Strings.EMPTY_ARRAY);
265+
assertThat(filteredMap.size(), equalTo(1));
266+
assertThat(((List<?>) filteredMap.get("array")), hasSize(1));
267+
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(0)).size(), equalTo(2));
269268

270269
map.clear();
271270
map.put("field", "value");
@@ -274,16 +273,16 @@ public void testNestedFiltering() {
274273
put("field", "value");
275274
put("field2", "value2");
276275
}});
277-
falteredMap = XContentMapValues.filter(map, new String[]{"obj.field"}, Strings.EMPTY_ARRAY);
278-
assertThat(falteredMap.size(), equalTo(1));
279-
assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(1));
280-
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));
276+
filteredMap = XContentMapValues.filter(map, new String[]{"obj.field"}, Strings.EMPTY_ARRAY);
277+
assertThat(filteredMap.size(), equalTo(1));
278+
assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(1));
279+
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field"), equalTo("value"));
281280

282-
falteredMap = XContentMapValues.filter(map, new String[]{"obj.*"}, Strings.EMPTY_ARRAY);
283-
assertThat(falteredMap.size(), equalTo(1));
284-
assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(2));
285-
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));
286-
assertThat((String) ((Map<String, Object>) falteredMap.get("obj")).get("field2"), equalTo("value2"));
281+
filteredMap = XContentMapValues.filter(map, new String[]{"obj.*"}, Strings.EMPTY_ARRAY);
282+
assertThat(filteredMap.size(), equalTo(1));
283+
assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(2));
284+
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field"), equalTo("value"));
285+
assertThat((String) ((Map<String, Object>) filteredMap.get("obj")).get("field2"), equalTo("value2"));
287286

288287
}
289288

@@ -325,7 +324,7 @@ public void testCompleteObjectFiltering() {
325324

326325
filteredMap = XContentMapValues.filter(map, new String[]{"array"}, new String[]{"*.field2"});
327326
assertThat(filteredMap.size(), equalTo(1));
328-
assertThat(((List) filteredMap.get("array")).size(), equalTo(2));
327+
assertThat(((List<?>) filteredMap.get("array")), hasSize(2));
329328
assertThat((Integer) ((List) filteredMap.get("array")).get(0), equalTo(1));
330329
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).size(), equalTo(1));
331330
assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).get("field").toString(), equalTo("value"));
@@ -438,20 +437,20 @@ public void testNotOmittingObjectWithNestedExcludedObject() throws Exception {
438437

439438
assertThat(filteredSource.size(), equalTo(1));
440439
assertThat(filteredSource, hasKey("obj1"));
441-
assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));
440+
assertThat(((Map) filteredSource.get("obj1")).size(), equalTo(0));
442441

443442
// explicit include
444443
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"obj1"}, new String[]{"*.obj2"});
445444
assertThat(filteredSource.size(), equalTo(1));
446445
assertThat(filteredSource, hasKey("obj1"));
447-
assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));
446+
assertThat(((Map) filteredSource.get("obj1")).size(), equalTo(0));
448447

449448
// wild card include
450449
filteredSource = XContentMapValues.filter(mapTuple.v2(), new String[]{"*.obj2"}, new String[]{"*.obj3"});
451450
assertThat(filteredSource.size(), equalTo(1));
452451
assertThat(filteredSource, hasKey("obj1"));
453452
assertThat(((Map<String, Object>) filteredSource.get("obj1")), hasKey("obj2"));
454-
assertThat(((Map) ((Map) filteredSource.get("obj1")).get("obj2")).size(), Matchers.equalTo(0));
453+
assertThat(((Map) ((Map) filteredSource.get("obj1")).get("obj2")).size(), equalTo(0));
455454
}
456455

457456
@SuppressWarnings({"unchecked"})
@@ -591,4 +590,15 @@ public void testSharedPrefixes() {
591590
assertEquals(Collections.singletonMap("foobar", 2), XContentMapValues.filter(map, new String[] {"foobar"}, new String[0]));
592591
assertEquals(Collections.singletonMap("foobaz", 3), XContentMapValues.filter(map, new String[0], new String[] {"foobar"}));
593592
}
593+
594+
public void testPrefix() {
595+
Map<String, Object> map = new HashMap<>();
596+
map.put("photos", Arrays.asList(new String[] {"foo", "bar"}));
597+
map.put("photosCount", 2);
598+
599+
Map<String, Object> filtered = XContentMapValues.filter(map, new String[] {"photosCount"}, new String[0]);
600+
Map<String, Object> expected = new HashMap<>();
601+
expected.put("photosCount", 2);
602+
assertEquals(expected, filtered);
603+
}
594604
}

0 commit comments

Comments
 (0)