private static Map<String, Object> flatten(Map<String, Object> map) {
    return map.entrySet().stream().flatMap(JsonUtils::flatten)
        .collect(LinkedHashMap::new, (m, e) -> m.put("/" + e.getKey(), e.getValue()), LinkedHashMap::putAll);
  }
@Test
  public void testFlatten()
      throws IOException {
    JsonIndexConfig jsonIndexConfig = new JsonIndexConfig();
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("null");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("123");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 1);
      assertEquals(flattenedRecords.get(0), Collections.singletonMap("", "123"));
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("[]");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("[1,2,3]");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 3);
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.size(), 2);
      assertEquals(flattenedRecord0.get(".$index"), "0");
      assertEquals(flattenedRecord0.get("."), "1");
      Map<String, String> flattenedRecord1 = flattenedRecords.get(1);
      assertEquals(flattenedRecord1.size(), 2);
      assertEquals(flattenedRecord1.get(".$index"), "1");
      assertEquals(flattenedRecord1.get("."), "2");
      Map<String, String> flattenedRecord2 = flattenedRecords.get(2);
      assertEquals(flattenedRecord2.size(), 2);
      assertEquals(flattenedRecord2.get(".$index"), "2");
      assertEquals(flattenedRecord2.get("."), "3");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("[1,[2,3],[4,[5,6]]]]");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 6);
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.size(), 2);
      assertEquals(flattenedRecord0.get(".$index"), "0");
      assertEquals(flattenedRecord0.get("."), "1");
      Map<String, String> flattenedRecord1 = flattenedRecords.get(1);
      assertEquals(flattenedRecord1.size(), 3);
      assertEquals(flattenedRecord1.get(".$index"), "1");
      assertEquals(flattenedRecord1.get("..$index"), "0");
      assertEquals(flattenedRecord1.get(".."), "2");
      Map<String, String> flattenedRecord2 = flattenedRecords.get(2);
      assertEquals(flattenedRecord2.size(), 3);
      assertEquals(flattenedRecord2.get(".$index"), "1");
      assertEquals(flattenedRecord2.get("..$index"), "1");
      assertEquals(flattenedRecord2.get(".."), "3");
      Map<String, String> flattenedRecord3 = flattenedRecords.get(3);
      assertEquals(flattenedRecord3.size(), 3);
      assertEquals(flattenedRecord3.get(".$index"), "2");
      assertEquals(flattenedRecord3.get("..$index"), "0");
      assertEquals(flattenedRecord3.get(".."), "4");
      Map<String, String> flattenedRecord4 = flattenedRecords.get(4);
      assertEquals(flattenedRecord4.size(), 4);
      assertEquals(flattenedRecord4.get(".$index"), "2");
      assertEquals(flattenedRecord4.get("..$index"), "1");
      assertEquals(flattenedRecord4.get("...$index"), "0");
      assertEquals(flattenedRecord4.get("..."), "5");
      Map<String, String> flattenedRecord5 = flattenedRecords.get(5);
      assertEquals(flattenedRecord5.size(), 4);
      assertEquals(flattenedRecord5.get(".$index"), "2");
      assertEquals(flattenedRecord5.get("..$index"), "1");
      assertEquals(flattenedRecord5.get("...$index"), "1");
      assertEquals(flattenedRecord5.get("..."), "6");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("{}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("{\"key\":{}}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("[{},{},{}]");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("{\"key\":[]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertTrue(flattenedRecords.isEmpty());
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode("{\"name\":\"adam\",\"age\":20}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 1);
      Map<String, String> flattenedRecord = flattenedRecords.get(0);
      assertEquals(flattenedRecord.size(), 2);
      assertEquals(flattenedRecord.get(".name"), "adam");
      assertEquals(flattenedRecord.get(".age"), "20");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "[{\"country\":\"us\",\"street\":\"main st\",\"number\":1},{\"country\":\"ca\",\"street\":\"second st\","
              + "\"number\":2}]");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 2);
      for (Map<String, String> flattenedRecord : flattenedRecords) {
        assertEquals(flattenedRecord.size(), 4);
        assertTrue(flattenedRecord.containsKey(".$index"));
        assertTrue(flattenedRecord.containsKey("..country"));
        assertTrue(flattenedRecord.containsKey("..street"));
        assertTrue(flattenedRecord.containsKey("..number"));
      }
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.get(".$index"), "0");
      assertEquals(flattenedRecord0.get("..country"), "us");
      assertEquals(flattenedRecord0.get("..street"), "main st");
      assertEquals(flattenedRecord0.get("..number"), "1");
      Map<String, String> flattenedRecord1 = flattenedRecords.get(1);
      assertEquals(flattenedRecord1.get(".$index"), "1");
      assertEquals(flattenedRecord1.get("..country"), "ca");
      assertEquals(flattenedRecord1.get("..street"), "second st");
      assertEquals(flattenedRecord1.get("..number"), "2");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "{\"name\":\"adam\",\"addresses\":[{\"country\":\"us\",\"street\":\"main st\",\"number\":1},"
              + "{\"country\":\"ca\",\"street\":\"second st\",\"number\":2}]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 2);
      for (Map<String, String> flattenedRecord : flattenedRecords) {
        assertEquals(flattenedRecord.size(), 5);
        assertEquals(flattenedRecord.get(".name"), "adam");
        assertTrue(flattenedRecord.containsKey(".addresses.$index"));
        assertTrue(flattenedRecord.containsKey(".addresses..country"));
        assertTrue(flattenedRecord.containsKey(".addresses..street"));
        assertTrue(flattenedRecord.containsKey(".addresses..number"));
      }
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord0.get(".addresses..country"), "us");
      assertEquals(flattenedRecord0.get(".addresses..street"), "main st");
      assertEquals(flattenedRecord0.get(".addresses..number"), "1");
      Map<String, String> flattenedRecord1 = flattenedRecords.get(1);
      assertEquals(flattenedRecord1.get(".addresses.$index"), "1");
      assertEquals(flattenedRecord1.get(".addresses..country"), "ca");
      assertEquals(flattenedRecord1.get(".addresses..street"), "second st");
      assertEquals(flattenedRecord1.get(".addresses..number"), "2");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "{\"name\":\"adam\",\"age\":20,\"addresses\":[{\"country\":\"us\",\"street\":\"main st\",\"number\":1},"
              + "{\"country\":\"ca\",\"street\":\"second st\",\"number\":2}],\"skills\":[\"english\","
              + "\"programming\"]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 4);
      for (Map<String, String> flattenedRecord : flattenedRecords) {
        assertEquals(flattenedRecord.size(), 8);
        assertEquals(flattenedRecord.get(".name"), "adam");
        assertEquals(flattenedRecord.get(".age"), "20");
        assertTrue(flattenedRecord.containsKey(".addresses.$index"));
        assertTrue(flattenedRecord.containsKey(".addresses..country"));
        assertTrue(flattenedRecord.containsKey(".addresses..street"));
        assertTrue(flattenedRecord.containsKey(".addresses..number"));
        assertTrue(flattenedRecord.containsKey(".skills.$index"));
        assertTrue(flattenedRecord.containsKey(".skills."));
      }
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord0.get(".addresses..country"), "us");
      assertEquals(flattenedRecord0.get(".addresses..street"), "main st");
      assertEquals(flattenedRecord0.get(".addresses..number"), "1");
      assertEquals(flattenedRecord0.get(".skills.$index"), "0");
      assertEquals(flattenedRecord0.get(".skills."), "english");
      Map<String, String> flattenedRecord3 = flattenedRecords.get(3);
      assertEquals(flattenedRecord3.get(".addresses.$index"), "1");
      assertEquals(flattenedRecord3.get(".addresses..country"), "ca");
      assertEquals(flattenedRecord3.get(".addresses..street"), "second st");
      assertEquals(flattenedRecord3.get(".addresses..number"), "2");
      assertEquals(flattenedRecord3.get(".skills.$index"), "1");
      assertEquals(flattenedRecord3.get(".skills."), "programming");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "{\"name\":\"bob\",\"age\":null,\"addresses\":[{\"country\":\"us\",\"street\":\"main st\"}],\"skills\":[],"
              + "\"hobbies\":[null]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 1);
      Map<String, String> flattenedRecord = flattenedRecords.get(0);
      assertEquals(flattenedRecord.size(), 4);
      assertEquals(flattenedRecord.get(".name"), "bob");
      assertEquals(flattenedRecord.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord.get(".addresses..country"), "us");
      assertEquals(flattenedRecord.get(".addresses..street"), "main st");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "{\"name\":\"bob\",\"age\":null,\"addresses\":[{\"country\":\"us\",\"street\":\"main st\"}],\"skills\":[],"
              + "\"hobbies\":[null," + "\"football\"]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 1);
      Map<String, String> flattenedRecord = flattenedRecords.get(0);
      assertEquals(flattenedRecord.size(), 6);
      assertEquals(flattenedRecord.get(".name"), "bob");
      assertEquals(flattenedRecord.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord.get(".addresses..country"), "us");
      assertEquals(flattenedRecord.get(".addresses..street"), "main st");
      assertEquals(flattenedRecord.get(".hobbies.$index"), "1");
      assertEquals(flattenedRecord.get(".hobbies."), "football");
    }
    {
      JsonNode jsonNode = JsonUtils.stringToJsonNode(
          "{\"name\":\"charles\",\"addresses\":[{\"country\":\"us\",\"street\":\"main st\",\"types\":[\"home\","
              + "\"office\"]}," + "{\"country\":\"ca\",\"street\":\"second st\"}]}");
      List<Map<String, String>> flattenedRecords = JsonUtils.flatten(jsonNode, jsonIndexConfig);
      assertEquals(flattenedRecords.size(), 3);
      Map<String, String> flattenedRecord0 = flattenedRecords.get(0);
      assertEquals(flattenedRecord0.size(), 6);
      assertEquals(flattenedRecord0.get(".name"), "charles");
      assertEquals(flattenedRecord0.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord0.get(".addresses..country"), "us");
      assertEquals(flattenedRecord0.get(".addresses..street"), "main st");
      assertEquals(flattenedRecord0.get(".addresses..types.$index"), "0");
      assertEquals(flattenedRecord0.get(".addresses..types."), "home");
      Map<String, String> flattenedRecord1 = flattenedRecords.get(1);
      assertEquals(flattenedRecord1.size(), 6);
      assertEquals(flattenedRecord1.get(".name"), "charles");
      assertEquals(flattenedRecord1.get(".addresses.$index"), "0");
      assertEquals(flattenedRecord1.get(".addresses..country"), "us");
      assertEquals(flattenedRecord1.get(".addresses..street"), "main st");
      assertEquals(flattenedRecord1.get(".addresses..types.$index"), "1");
      assertEquals(flattenedRecord1.get(".addresses..types."), "office");
      Map<String, String> flattenedRecord2 = flattenedRecords.get(2);
      assertEquals(flattenedRecord2.size(), 4);
      assertEquals(flattenedRecord2.get(".name"), "charles");
      assertEquals(flattenedRecord2.get(".addresses.$index"), "1");
      assertEquals(flattenedRecord2.get(".addresses..country"), "ca");
      assertEquals(flattenedRecord2.get(".addresses..street"), "second st");
    }
  }