@SuppressWarnings("unchecked")
  public void testNestedFiltering() {
    Map<String, Object> map = new HashMap<>();
    map.put("field", "value");
    map.put(
        "array",
        Arrays.asList(
            1,
            new HashMap<String, Object>() {
              {
                put("nested", 2);
                put("nested_2", 3);
              }
            }));
    Map<String, Object> falteredMap =
        XContentMapValues.filter(map, new String[] {"array.nested"}, Strings.EMPTY_ARRAY);
    assertThat(falteredMap.size(), equalTo(1));

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

    falteredMap = XContentMapValues.filter(map, new String[] {"array.*"}, Strings.EMPTY_ARRAY);
    assertThat(falteredMap.size(), equalTo(1));
    assertThat((Integer) ((List) falteredMap.get("array")).get(0), equalTo(1));
    assertThat(((Map<String, Object>) ((List) falteredMap.get("array")).get(1)).size(), equalTo(2));

    map.clear();
    map.put("field", "value");
    map.put(
        "obj",
        new HashMap<String, Object>() {
          {
            put("field", "value");
            put("field2", "value2");
          }
        });
    falteredMap = XContentMapValues.filter(map, new String[] {"obj.field"}, Strings.EMPTY_ARRAY);
    assertThat(falteredMap.size(), equalTo(1));
    assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(1));
    assertThat(
        (String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));

    falteredMap = XContentMapValues.filter(map, new String[] {"obj.*"}, Strings.EMPTY_ARRAY);
    assertThat(falteredMap.size(), equalTo(1));
    assertThat(((Map<String, Object>) falteredMap.get("obj")).size(), equalTo(2));
    assertThat(
        (String) ((Map<String, Object>) falteredMap.get("obj")).get("field"), equalTo("value"));
    assertThat(
        (String) ((Map<String, Object>) falteredMap.get("obj")).get("field2"), equalTo("value2"));
  }
  public void testSharedPrefixes() {
    Map<String, Object> map = new HashMap<>();
    map.put("foobar", 2);
    map.put("foobaz", 3);

    assertEquals(
        Collections.singletonMap("foobar", 2),
        XContentMapValues.filter(map, new String[] {"foobar"}, new String[0]));
    assertEquals(
        Collections.singletonMap("foobaz", 3),
        XContentMapValues.filter(map, new String[0], new String[] {"foobar"}));
  }
  public void testSupplementaryCharactersInPaths() {
    Map<String, Object> map = new HashMap<>();
    map.put("搜索", 2);
    map.put("指数", 3);

    assertEquals(
        Collections.singletonMap("搜索", 2),
        XContentMapValues.filter(map, new String[] {"搜索"}, new String[0]));
    assertEquals(
        Collections.singletonMap("指数", 3),
        XContentMapValues.filter(map, new String[0], new String[] {"搜索"}));
  }
  @SuppressWarnings("unchecked")
  public void testCompleteObjectFiltering() {
    Map<String, Object> map = new HashMap<>();
    map.put("field", "value");
    map.put(
        "obj",
        new HashMap<String, Object>() {
          {
            put("field", "value");
            put("field2", "value2");
          }
        });
    map.put(
        "array",
        Arrays.asList(
            1,
            new HashMap<String, Object>() {
              {
                put("field", "value");
                put("field2", "value2");
              }
            }));

    Map<String, Object> filteredMap =
        XContentMapValues.filter(map, new String[] {"obj"}, Strings.EMPTY_ARRAY);
    assertThat(filteredMap.size(), equalTo(1));
    assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(2));
    assertThat(
        ((Map<String, Object>) filteredMap.get("obj")).get("field").toString(), equalTo("value"));
    assertThat(
        ((Map<String, Object>) filteredMap.get("obj")).get("field2").toString(), equalTo("value2"));

    filteredMap = XContentMapValues.filter(map, new String[] {"obj"}, new String[] {"*.field2"});
    assertThat(filteredMap.size(), equalTo(1));
    assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(1));
    assertThat(
        ((Map<String, Object>) filteredMap.get("obj")).get("field").toString(), equalTo("value"));

    filteredMap = XContentMapValues.filter(map, new String[] {"array"}, new String[] {});
    assertThat(filteredMap.size(), equalTo(1));
    assertThat(((List) filteredMap.get("array")).size(), equalTo(2));
    assertThat((Integer) ((List) filteredMap.get("array")).get(0), equalTo(1));
    assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).size(), equalTo(2));

    filteredMap = XContentMapValues.filter(map, new String[] {"array"}, new String[] {"*.field2"});
    assertThat(filteredMap.size(), equalTo(1));
    assertThat(((List) filteredMap.get("array")).size(), equalTo(2));
    assertThat((Integer) ((List) filteredMap.get("array")).get(0), equalTo(1));
    assertThat(((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).size(), equalTo(1));
    assertThat(
        ((Map<String, Object>) ((List) filteredMap.get("array")).get(1)).get("field").toString(),
        equalTo("value"));
  }
 public void testFilterWithEmptyIncludesExcludes() {
   Map<String, Object> map = new HashMap<>();
   map.put("field", "value");
   Map<String, Object> filteredMap =
       XContentMapValues.filter(map, Strings.EMPTY_ARRAY, Strings.EMPTY_ARRAY);
   assertThat(filteredMap.size(), equalTo(1));
   assertThat(filteredMap.get("field").toString(), equalTo("value"));
 }
  @SuppressWarnings("unchecked")
  public void testFilterIncludesUsingStarPrefix() {
    Map<String, Object> map = new HashMap<>();
    map.put("field", "value");
    map.put(
        "obj",
        new HashMap<String, Object>() {
          {
            put("field", "value");
            put("field2", "value2");
          }
        });
    map.put(
        "n_obj",
        new HashMap<String, Object>() {
          {
            put("n_field", "value");
            put("n_field2", "value2");
          }
        });

    Map<String, Object> filteredMap =
        XContentMapValues.filter(map, new String[] {"*.field2"}, Strings.EMPTY_ARRAY);
    assertThat(filteredMap.size(), equalTo(1));
    assertThat(filteredMap, hasKey("obj"));
    assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(1));
    assertThat(((Map<String, Object>) filteredMap.get("obj")), hasKey("field2"));

    // only objects
    filteredMap = XContentMapValues.filter(map, new String[] {"*.*"}, Strings.EMPTY_ARRAY);
    assertThat(filteredMap.size(), equalTo(2));
    assertThat(filteredMap, hasKey("obj"));
    assertThat(((Map<String, Object>) filteredMap.get("obj")).size(), equalTo(2));
    assertThat(filteredMap, hasKey("n_obj"));
    assertThat(((Map<String, Object>) filteredMap.get("n_obj")).size(), equalTo(2));

    filteredMap = XContentMapValues.filter(map, new String[] {"*"}, new String[] {"*.*2"});
    assertThat(filteredMap.size(), equalTo(3));
    assertThat(filteredMap, hasKey("field"));
    assertThat(filteredMap, hasKey("obj"));
    assertThat(((Map) filteredMap.get("obj")).size(), equalTo(1));
    assertThat(((Map<String, Object>) filteredMap.get("obj")), hasKey("field"));
    assertThat(filteredMap, hasKey("n_obj"));
    assertThat(((Map<String, Object>) filteredMap.get("n_obj")).size(), equalTo(1));
    assertThat(((Map<String, Object>) filteredMap.get("n_obj")), hasKey("n_field"));
  }
 public void testPrefixedNamesFilteringTest() {
   Map<String, Object> map = new HashMap<>();
   map.put("obj", "value");
   map.put("obj_name", "value_name");
   Map<String, Object> filterdMap =
       XContentMapValues.filter(map, new String[] {"obj_name"}, Strings.EMPTY_ARRAY);
   assertThat(filterdMap.size(), equalTo(1));
   assertThat((String) filterdMap.get("obj_name"), equalTo("value_name"));
 }
  public void testThatFilterIncludesEmptyObjectWhenUsingIncludes() throws Exception {
    XContentBuilder builder =
        XContentFactory.jsonBuilder().startObject().startObject("obj").endObject().endObject();

    Tuple<XContentType, Map<String, Object>> mapTuple =
        XContentHelper.convertToMap(builder.bytes(), true);
    Map<String, Object> filteredSource =
        XContentMapValues.filter(mapTuple.v2(), new String[] {"obj"}, Strings.EMPTY_ARRAY);

    assertThat(mapTuple.v2(), equalTo(filteredSource));
  }
  public void testDotsInFieldNames() {
    Map<String, Object> map = new HashMap<>();
    map.put("foo.bar", 2);
    Map<String, Object> sub = new HashMap<>();
    sub.put("baz", 3);
    map.put("foo", sub);
    map.put("quux", 5);

    // dots in field names in includes
    Map<String, Object> filtered =
        XContentMapValues.filter(map, new String[] {"foo"}, new String[0]);
    Map<String, Object> expected = new HashMap<>(map);
    expected.remove("quux");
    assertEquals(expected, filtered);

    // dots in field names in excludes
    filtered = XContentMapValues.filter(map, new String[0], new String[] {"foo"});
    expected = new HashMap<>(map);
    expected.keySet().retainAll(Collections.singleton("quux"));
    assertEquals(expected, filtered);
  }
  @SuppressWarnings({"unchecked"})
  public void testNotOmittingObjectWithNestedExcludedObject() throws Exception {
    XContentBuilder builder =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("obj1")
            .startObject("obj2")
            .startObject("obj3")
            .endObject()
            .endObject()
            .endObject()
            .endObject();

    // implicit include
    Tuple<XContentType, Map<String, Object>> mapTuple =
        XContentHelper.convertToMap(builder.bytes(), true);
    Map<String, Object> filteredSource =
        XContentMapValues.filter(mapTuple.v2(), Strings.EMPTY_ARRAY, new String[] {"*.obj2"});

    assertThat(filteredSource.size(), equalTo(1));
    assertThat(filteredSource, hasKey("obj1"));
    assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));

    // explicit include
    filteredSource =
        XContentMapValues.filter(mapTuple.v2(), new String[] {"obj1"}, new String[] {"*.obj2"});
    assertThat(filteredSource.size(), equalTo(1));
    assertThat(filteredSource, hasKey("obj1"));
    assertThat(((Map) filteredSource.get("obj1")).size(), Matchers.equalTo(0));

    // wild card include
    filteredSource =
        XContentMapValues.filter(mapTuple.v2(), new String[] {"*.obj2"}, new String[] {"*.obj3"});
    assertThat(filteredSource.size(), equalTo(1));
    assertThat(filteredSource, hasKey("obj1"));
    assertThat(((Map<String, Object>) filteredSource.get("obj1")), hasKey("obj2"));
    assertThat(((Map) ((Map) filteredSource.get("obj1")).get("obj2")).size(), Matchers.equalTo(0));
  }
  public void testNotOmittingObjectsWithExcludedProperties() throws Exception {
    XContentBuilder builder =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("obj")
            .field("f1", "v1")
            .endObject()
            .endObject();

    Tuple<XContentType, Map<String, Object>> mapTuple =
        XContentHelper.convertToMap(builder.bytes(), true);
    Map<String, Object> filteredSource =
        XContentMapValues.filter(mapTuple.v2(), Strings.EMPTY_ARRAY, new String[] {"obj.f1"});

    assertThat(filteredSource.size(), equalTo(1));
    assertThat(filteredSource, hasKey("obj"));
    assertThat(((Map) filteredSource.get("obj")).size(), equalTo(0));
  }
 public Object filter(String[] includes, String[] excludes) {
   return XContentMapValues.filter(loadSourceIfNeeded(), includes, excludes);
 }
  public void testFilter() throws Exception {
    XContentBuilder builder =
        XContentFactory.jsonBuilder()
            .startObject()
            .field("test1", "value1")
            .field("test2", "value2")
            .field("something_else", "value3")
            .endObject();

    Map<String, Object> source;
    try (XContentParser parser =
        XContentFactory.xContent(XContentType.JSON).createParser(builder.string())) {
      source = parser.map();
    }
    Map<String, Object> filter =
        XContentMapValues.filter(source, new String[] {"test1"}, Strings.EMPTY_ARRAY);
    assertThat(filter.size(), equalTo(1));
    assertThat(filter.get("test1").toString(), equalTo("value1"));

    filter = XContentMapValues.filter(source, new String[] {"test*"}, Strings.EMPTY_ARRAY);
    assertThat(filter.size(), equalTo(2));
    assertThat(filter.get("test1").toString(), equalTo("value1"));
    assertThat(filter.get("test2").toString(), equalTo("value2"));

    filter = XContentMapValues.filter(source, Strings.EMPTY_ARRAY, new String[] {"test1"});
    assertThat(filter.size(), equalTo(2));
    assertThat(filter.get("test2").toString(), equalTo("value2"));
    assertThat(filter.get("something_else").toString(), equalTo("value3"));

    // more complex object...
    builder =
        XContentFactory.jsonBuilder()
            .startObject()
            .startObject("path1")
            .startArray("path2")
            .startObject()
            .field("test", "value1")
            .endObject()
            .startObject()
            .field("test", "value2")
            .endObject()
            .endArray()
            .endObject()
            .field("test1", "value1")
            .endObject();

    try (XContentParser parser =
        XContentFactory.xContent(XContentType.JSON).createParser(builder.string())) {
      source = parser.map();
    }
    filter = XContentMapValues.filter(source, new String[] {"path1"}, Strings.EMPTY_ARRAY);
    assertThat(filter.size(), equalTo(1));

    filter = XContentMapValues.filter(source, new String[] {"path1*"}, Strings.EMPTY_ARRAY);
    assertThat(filter.get("path1"), equalTo(source.get("path1")));
    assertThat(filter.containsKey("test1"), equalTo(false));

    filter = XContentMapValues.filter(source, new String[] {"test1*"}, Strings.EMPTY_ARRAY);
    assertThat(filter.get("test1"), equalTo(source.get("test1")));
    assertThat(filter.containsKey("path1"), equalTo(false));

    filter = XContentMapValues.filter(source, new String[] {"path1.path2.*"}, Strings.EMPTY_ARRAY);
    assertThat(filter.get("path1"), equalTo(source.get("path1")));
    assertThat(filter.containsKey("test1"), equalTo(false));
  }