From 84936d57adfb3fc83253ed5c677ad952f8f4ae3b Mon Sep 17 00:00:00 2001 From: Alexander Reelsen Date: Fri, 20 Jan 2017 12:22:20 +0100 Subject: [PATCH] Watcher: Fix XContentFilterKeysUtils when using nested lists (elastic/elasticsearch#4635) The ability to filter JSON inside of arrays was stopping after the first element was found. Closes elastic/elasticsearch#4614 Original commit: elastic/x-pack-elasticsearch@452cf1c49d967f5c0c526956b098157d3144c0b4 --- .../support/XContentFilterKeysUtils.java | 12 +++- .../watcher/support/FilterXContentTests.java | 59 +++++++++++++++++++ 2 files changed, 68 insertions(+), 3 deletions(-) diff --git a/elasticsearch/src/main/java/org/elasticsearch/xpack/watcher/support/XContentFilterKeysUtils.java b/elasticsearch/src/main/java/org/elasticsearch/xpack/watcher/support/XContentFilterKeysUtils.java index 7acad5bd080..ef689fe469e 100644 --- a/elasticsearch/src/main/java/org/elasticsearch/xpack/watcher/support/XContentFilterKeysUtils.java +++ b/elasticsearch/src/main/java/org/elasticsearch/xpack/watcher/support/XContentFilterKeysUtils.java @@ -79,19 +79,25 @@ public final class XContentFilterKeysUtils { if (state.includeKey) { data.put(state.currentFieldName(), parser.text()); } - state.previousField(); + if (isOutsideOfArray) { + state.previousField(); + } break; case VALUE_NUMBER: if (state.includeKey) { data.put(state.currentFieldName(), parser.numberValue()); } - state.previousField(); + if (isOutsideOfArray) { + state.previousField(); + } break; case VALUE_BOOLEAN: if (state.includeKey) { data.put(state.currentFieldName(), parser.booleanValue()); } - state.previousField(); + if (isOutsideOfArray) { + state.previousField(); + } break; } } diff --git a/elasticsearch/src/test/java/org/elasticsearch/xpack/watcher/support/FilterXContentTests.java b/elasticsearch/src/test/java/org/elasticsearch/xpack/watcher/support/FilterXContentTests.java index 417d2a31116..2f0d9906682 100644 --- a/elasticsearch/src/test/java/org/elasticsearch/xpack/watcher/support/FilterXContentTests.java +++ b/elasticsearch/src/test/java/org/elasticsearch/xpack/watcher/support/FilterXContentTests.java @@ -9,8 +9,10 @@ import org.elasticsearch.common.collect.MapBuilder; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.test.ESTestCase; +import org.elasticsearch.xpack.watcher.support.xcontent.ObjectPath; import org.hamcrest.Matchers; +import java.io.IOException; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; @@ -23,6 +25,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.instanceOf; +import static org.hamcrest.Matchers.is; public class FilterXContentTests extends ESTestCase { public void testPayloadFiltering() throws Exception { @@ -136,6 +139,62 @@ public class FilterXContentTests extends ESTestCase { assertThat(buckets.get(1).keySet(), containsInAnyOrder("foo")); } + // issue #4614 + public void testNestedArraysWork() throws Exception { + XContentBuilder builder = jsonBuilder().startObject().startArray("buckets") + .startObject().startObject("foo").field("spam", "eggs").endObject().endObject() + .startObject().startObject("foo").field("spam", "eggs2").endObject().endObject() + .startObject().startObject("foo").field("spam", "eggs3").endObject().endObject() + .endArray().endObject(); + + XContentParser parser = createParser(builder); + + assertArrayValues(parser, "buckets.foo.spam", "eggs", "eggs2", "eggs3"); + } + + private void assertArrayValues(XContentParser parser, String key, Object ... expectedValues) throws IOException { + Set keys = new HashSet<>(); + keys.add(key); + Map filteredData = XContentFilterKeysUtils.filterMapOrdered(keys, parser); + for (int i = 0; i < expectedValues.length; i++) { + if (expectedValues[i] instanceof String) { + String data = ObjectPath.eval("buckets." + i + ".foo.spam", filteredData); + assertThat(data, is(expectedValues[i])); + } else if (expectedValues[i] instanceof Integer) { + int data = ObjectPath.eval("buckets." + i + ".foo.spam", filteredData); + assertThat(data, is(expectedValues[i])); + } else if (expectedValues[i] instanceof Boolean) { + boolean data = ObjectPath.eval("buckets." + i + ".foo.spam", filteredData); + assertThat(data, is(expectedValues[i])); + } + } + } + + public void testNestedArraysWorkWithNumbers() throws Exception { + XContentBuilder builder = jsonBuilder().startObject().startArray("buckets") + .startObject().startObject("foo").field("spam", 0).endObject().endObject() + .startObject().startObject("foo").field("spam", 1).endObject().endObject() + .startObject().startObject("foo").field("spam", 2).endObject().endObject() + .endArray().endObject(); + + XContentParser parser = createParser(builder); + + assertArrayValues(parser, "buckets.foo.spam", 0, 1, 2); + } + + public void testNestedArraysWorkWithBooleans() throws Exception { + boolean[] bools = new boolean[] { randomBoolean(), randomBoolean(), randomBoolean() }; + + XContentBuilder builder = jsonBuilder().startObject().startArray("buckets") + .startObject().startObject("foo").field("spam", bools[0]).endObject().endObject() + .startObject().startObject("foo").field("spam", bools[1]).endObject().endObject() + .startObject().startObject("foo").field("spam", bools[2]).endObject().endObject() + .endArray().endObject(); + + XContentParser parser = createParser(builder); + + assertArrayValues(parser, "buckets.foo.spam", bools); + } @SuppressWarnings("unchecked") private static Map selectMap(Map data, String... path) {