Как получить вложенный элемент объекта json с помощью Java

У меня есть следующий файл json test.json

{
  "type" : "object",
  "id" : "123",
  "title" : "Test",
  "properties" : {
    "_picnic" : {
      "type" : "boolean"
....

Я могу получить значение ключа первого уровня, используя следующий код. Например. за type я получаю object

public static void main(String[] args){

        String exampleRequest = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            exampleRequest = FileUtils.readFileToString(new File("src/main/resources/test.json"), StandardCharsets.UTF_8);
            JsonNode jsonNode = objectMapper.readTree(exampleRequest);

            String type = jsonNode.get("type").asText();
            System.out.println(type);

        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        // System.out.println(exampleRequest);


    }

Однако я не получаю никакого ответа, когда пытаюсь получить значение для второго уровня. Например. если я сделаю

String type = jsonNode.get("_picnic").asText();
System.out.println(type);

OR the whole object e.g.

String type = jsonNode.get("properties").asText();
System.out.println(type);

Я пытался сделать properties._picnic или properties[0]_picnic, но безуспешно.

Возможно, это может вам помочь stackoverflow.com/questions/14898768/…

DaveR 12.04.2023 20:44
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
1
1
68
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

В документации к этому методу говорится (выделено мной):

Метод, возвращающий допустимое строковое представление значения контейнера, если узел является узлом значения (метод isValueNode() возвращает true), в противном случае пустая строка.

Согласно фрагменту текста json, которым вы поделились, и "properties", и "_picnic" являются объектами, а не значениями, поэтому вы получаете пустую строку. Кажется, вам нужно использовать метод get:

jsonNode.get("properties").get("_picnic").get("type").asText()

Спасибо за ответ, он получает значение типа, но почему он не дает мне блок для jsonNode.get("properties").get("_picnic").asText() или jsonNode.get("properties").asText()

Dr. Mian 12.04.2023 21:59

Я уже объяснил это в своем ответе, но я обновлю, чтобы немного уточнить.

dominicoder 12.04.2023 22:07

Итак, вы упомянули get, но не использовали его. Не могли бы вы добавить это и к ответу. Чтобы получить соответствующие объекты, используйте String type = String.valueOf(jsonNode.get("properties")); и String type = String.valueOf(jsonNode.get("properties").get("_picnic"));

Dr. Mian 13.04.2023 10:20

Я показал пример получения в своем исходном ответе. String type = String.valueOf(jsonNode.get("properties")); будет неправильным, поскольку в опубликованном вами JSON "properties" является объектом.

dominicoder 13.04.2023 16:26

Вы можете использовать рекурсию, чтобы упростить этот код. Просто вызовите getText с начальным узлом и переменным списком (массивом) путей. Он определит, нужно ли ему проверять объект или массив.

import java.io.*;
import java.nio.charset.StandardCharsets;
import org.apache.commons.io.FileUtils;
import com.fasterxml.jackson.databind.*;

public class NestedJson {
    public static void main(String[] args) {
        String exampleRequest = null;
        ObjectMapper objectMapper = new ObjectMapper();
        try {
            exampleRequest = FileUtils.readFileToString(new File("src/main/resources/test.json"),
                    StandardCharsets.UTF_8);
            JsonNode jsonNode = objectMapper.readTree(exampleRequest);
            System.out.println(getText(jsonNode, "type")); // object
            System.out.println(getText(jsonNode, "properties", "_picnic", "type")); // boolean
            System.out.println(getText(jsonNode, "stuff", "0", "foo")); // bar
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static String getText(JsonNode node, String... path) {
        return getText(node, 0, path);
    }

    private static String getText(JsonNode node, int cursor, String[] path) {
        if (node == null || path == null || path.length == 0)
            return null;
        if (cursor == path.length) {
            return node != null ? node.asText() : null;
        }
        if (node.isObject()) {
            return getText(node.get(path[cursor]), cursor + 1, path);
        } else if (node.isArray()) {
            return getText(node.get(Integer.parseInt(path[cursor])), cursor + 1, path);
        }
        return null;
    }
}

Изменено test.json:

{
  "type": "object",
  "id": "123",
  "title": "Test",
  "properties": {
    "_picnic": {
      "type": "boolean"
    }
  },
  "stuff": [
    {
      "foo": "bar"
    }
  ]
}

Спасибо, проверю и отчитаюсь.

Dr. Mian 12.04.2023 22:01

Я думаю, что в конечном итоге я ищу такое решение, но вместо того, чтобы передавать жестко закодированные аргументы, было бы неплохо использовать код, чтобы определить, является ли поступающий элемент массивом или объектом, и соответственно вызвать функцию.

Dr. Mian 13.04.2023 10:29

Другие вопросы по теме