«1. Введение

В этом руководстве мы рассмотрим несколько подходов к повторению JSONObject, простого представления JSON для Java.

Мы начнем с простого решения, а затем рассмотрим что-то более надежное.

2. Итерация по JSONObject

Давайте начнем с простого случая итерации JSON пар имя-значение:

{
  "name": "Cake",
  "cakeId": "0001",
  "cakeShape": "Heart"
}

Для этого мы можем просто перебрать ключи, используя метод keys() :

void handleJSONObject(JSONObject jsonObject) {
    jsonObject.keys().forEachRemaining(key -> {
        Object value = jsonObject.get(key);
        logger.info("Key: {0}\tValue: {1}", key, value);
    }
}

И наш вывод будет таким:

Key: name      Value: Cake
Key: cakeId    Value: 0001
Key: cakeShape Value: Heart

3. Обход объекта JSON

Но допустим, что у нас есть более сложная структура:

{
  "batters": [
    {
      "type": "Regular",
      "id": "1001"
    },
    {
      "type": "Chocolate",
      "id": "1002"
    },
    {
      "type": "BlueBerry",
      "id": "1003"
    }
  ],
  "name": "Cake",
  "cakeId": "0001"
}

Что означает перебор объекта ключи в данном случае?

Давайте посмотрим, что даст нам наш наивный подход с ключами():

Key: batters    Value: [{"type":"Regular","id":"1001"},{"type":"Chocolate","id":"1002"},
  {"type":"BlueBerry","id":"1003"}]
Key: name       Value: Cake
Key: cakeId     Value: 0001

Возможно, это не так полезно. Похоже, что в данном случае нам нужна не итерация, а обход.

Обход через JSONObject отличается от итерации по набору ключей JSONObject.

Для этого нам нужно также проверить тип значения. Давайте представим, что мы делаем это в отдельном методе:

void handleValue(Object value) {
    if (value instanceof JSONObject) {
        handleJSONObject((JSONObject) value);
    } else if (value instanceof JSONArray) {
        handleJSONArray((JSONArray) value);
    } else {
        logger.info("Value: {0}", value);
    }
}

Тогда наш подход все еще довольно похож:

void handleJSONObject(JSONObject jsonObject) {
    jsonObject.keys().forEachRemaining(key -> {
        Object value = jsonObject.get(key);
        logger.info("Key: {0}", key);
        handleValue(value);
    });
}

Единственное, что нам нужно подумать о том, как обрабатывать массивы.

4. Обход JSONArray

Давайте попробуем сохранить аналогичный подход с использованием итератора. Однако вместо вызова keys() мы будем вызывать iterator():

void handleJSONArray(JSONArray jsonArray) {
    jsonArray.iterator().forEachRemaining(element -> {
        handleValue(element)
    });
}

Теперь это решение является ограничивающим, поскольку мы комбинируем обход с действием, которое хотим выполнить. Распространенным подходом к их разделению является использование шаблона «Посетитель».

5. Заключение

В этой статье мы рассмотрели способ перебора JSONObject для простых пар имя-значение, проблему, связанную со сложными структурами, и технику обхода для ее решения.

Конечно, это был метод обхода в глубину, но мы могли бы сделать обход в ширину аналогичным образом.

Полный код примера доступен на Github.