Чтение значения вложенного ключа в JSON с помощью Java (Jackson)

Я новый программист Java, исходящий из фона в Python. У меня есть данные о погоде, которые собираются/возвращаются как JSON с вложенными в него ключами, и я не понимаю, как вывести значения в этой ситуации. Я уверен, что этот вопрос был задан раньше, но я клянусь, что у меня много раз, и я не могу найти ответ. Прямо сейчас я использую json-simple, но я попытался переключиться на Джексона и все еще не мог понять, как это сделать. Поскольку Jackson/Gson, по-видимому, являются наиболее часто используемыми библиотеками, мне бы хотелось увидеть пример, используя одну из этих библиотек. Ниже приведен образец данных, за которым следует код, который я написал до сих пор.

{
    "response": {
        "features": {
            "history": 1
        }
     },
    "history": {
        "date": {
            "pretty": "April 13, 2010",
            "year": "2010",
            "mon": "04",
            "mday": "13",
            "hour": "12",
            "min": "00",
            "tzname": "America/Los_Angeles"
        },
        ...
    }
}

Основная функция

public class Tester {

    public static void main(String args[]) throws MalformedURLException, IOException, ParseException {
        WundergroundAPI wu =  new WundergroundAPI("*******60fedd095");

        JSONObject json = wu.historical("San_Francisco", "CA", "20100413");

        System.out.println(json.toString());
        System.out.println();
        //This only returns 1 level. Further .get() calls throw an exception
        System.out.println(json.get("history"));
    }
}

Функция "историческая" вызывает другую функцию, которая возвращает объект JSONObject

public static JSONObject readJsonFromUrl(URL url) throws MalformedURLException, IOException, ParseException {

    InputStream inputStream = url.openStream();

    try {
        JSONParser parser = new JSONParser();
        BufferedReader buffReader = new BufferedReader(new InputStreamReader(inputStream, Charset.forName("UTF-8")));

        String jsonText = readAll(buffReader);
        JSONObject json = (JSONObject) parser.parse(jsonText);
        return json;
    } finally {
        inputStream.close();
    }
}

Ответ 1

С древовидной моделью Jackson (JsonNode) у вас есть "литералы" методов доступа ( "get" ), которые возвращают null для отсутствующего значения и "безопасные" accessors ( "путь" ), которые позволяют вам для перемещения "отсутствующих" узлов. Итак, например:

JsonNode root = mapper.readTree(inputSource);
int h = root.path("response").path("history").getValueAsInt();

который вернет значение на заданном пути или, если путь отсутствует, 0 (значение по умолчанию)

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

int h = root.at("/response/history").getValueAsInt();

Есть и другие способы, и часто удобнее моделировать вашу структуру как Обычный объект Java (POJO). Ваш контент может соответствовать:

public class Wrapper {
  public Response response;
} 
public class Response {
  public Map<String,Integer> features; // or maybe Map<String,Object>
  public List<HistoryItem> history;
}
public class HistoryItem {
  public MyDate date; // or just Map<String,String>
  // ... and so forth
}

и если да, то вы пройдете результирующие объекты, как и любые объекты Java.

Ответ 2

Откажитесь от Jackson ObjectMapper. Вы можете создать класс для моделирования JSON, а затем использовать метод ObjectMapper readValue для "десериализации" вашей JSON String в экземпляр вашего класса модели. И наоборот.

Ответ 3

Используйте Jsonpath

Целое число h = JsonPath.parse(json).read( "$. response.repository.history", Integer.class);

Ответ 4

Попробуйте API-интерфейс jpath. Это эквивалент xpath для данных JSON. Вы можете читать данные, предоставляя jpath, который будет перемещаться по данным JSON и возвращать запрошенное значение.

Этот Java-класс является реализацией, а также имеет примеры кода о том, как вызвать API.

https://github.com/satyapaul/jpath/blob/master/JSONDataReader.java

Readme -

https://github.com/satyapaul/jpath/blob/master/README.md

Пример:

Данные JSON:

{
    "data": [{
        "id": "13652355666_10154605514815667",
        "uid": "442637379090660",
        "userName": "fanffair",
        "userFullName": "fanffair",
        "userAction": "recommends",
        "pageid": "usatoday",
        "fanPageName": "USA TODAY",
        "description": "A missing Indonesian man was found inside a massive python on the island of Sulawesi, according to local authorities and news reports. ",
        "catid": "NewsAndMedia",
        "type": "link",
        "name": "Indonesian man swallowed whole by python",
        "picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "full_picture": "https:\/\/external.xx.fbcdn.net\/safe_image.php?d=AQBQf3loH5-XP6hH&w=130&h=130&url=https%3A%2F%2Fwww.gannett-cdn.com%2F-mm-%2F1bb682d12cfc4d1c1423ac6202f4a4e2205298e7%2Fc%3D0-5-1821-1034%26r%3Dx633%26c%3D1200x630%2Flocal%2F-%2Fmedia%2F2017%2F03%2F29%2FUSATODAY%2FUSATODAY%2F636263764866290525-Screen-Shot-2017-03-29-at-9.27.47-AM.jpg&cfs=1&_nc_hash=AQDssV84Gt83dH2A",
        "message": "Akbar Salubiro was reported missing after he failed to return from harvesting palm oil.",
        "link": "http:\/\/www.usatoday.com\/story\/news\/nation-now\/2017\/03\/29\/missing-indonesian-man-swallowed-whole-reticulated-python\/99771300\/",
        "source": "",
        "likes": {
            "summary": {
                "total_count": "500"
            }
        },
        "comments": {
            "summary": {
                "total_count": "61"
            }
        },
        "shares": {
            "count": "4"
        }
    }]

}

Фрагмент кода:

String jPath = "/data[Array][1]/likes[Object]/summary[Object]/total_count[String]";

String value = JSONDataReader.getStringValue(jPath, jsonData);