Возвращенные нулевые значения при разборе JSON данных с URL с использованием Джексона - PullRequest
0 голосов
/ 17 апреля 2020

Я пытаюсь получить некоторые данные из этого URL: https://www.topuniversities.com/sites/default/files/qs-rankings-data/397863.txt.

Вот фрагменты URL:

    {
  "data": [
    {
      "nid": "294850",
      "url": "/universities/massachusetts-institute-technology-mit",
      "title": "Massachusetts Institute of Technology (MIT)",
      "logo": "<img src=\"https://www.topuniversities.com/sites/default/files/massachusetts-institute-of-technology-mit_410_small_0.jpg\" alt=\"Massachusetts Institute of Technology (MIT) Logo\">",
      "core_id": "410",
      "score": "100",
      "rank_display": "1",
      "country": "United States",
      "region": "North America",
      "stars": "",
      "guide": "<a href=\"/where-to-study/north-america/united-states/guide\" class=\"guide-link\" target=\"_blank\">United States</a>"
    },
    {
      "nid": "297282",
      "url": "/universities/stanford-university",
      "title": "Stanford University",
      "logo": "<img src=\"https://www.topuniversities.com/sites/default/files/stanford-university_573_small_0.jpg\" alt=\"Stanford University Logo\">",
      "core_id": "573",
      "score": "98.6",
      "rank_display": "2",
      "country": "United States",
      "region": "North America",
      "stars": "",
      "guide": "<a href=\"/where-to-study/north-america/united-states/guide\" class=\"guide-link\" target=\"_blank\">United States</a>"
    }, (continue until the end....)

Я заинтересован только в получении "Заголовка" и "Страны", но мои коды возвращаются java.lang.NullPointerException, когда я пытаюсь прочитать значение.

Вот мой код Java в основном методе:

ObjectMapper mapper = new ObjectMapper();
        mapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        try {
            System.setProperty("http.agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/28.0.1500.29 Safari/537.36");
            UniversityList list = mapper.readValue(new URL("https://www.topuniversities.com/sites/default/files/qs-rankings-data/397863.txt"), UniversityList.class);

            for(University u : list.getUniversity()) {
                // Printing below, gives me null values
                System.out.println("Title: " + u.getTitle());
                System.out.println("Country: " + u.getCountry());
            }


        } catch (Exception e) {
            e.printStackTrace();
        }

А это класс DTO:

class UniversityList{
    private List<University> university;

    public List<University> getUniversity() {
        return university;
    }

    public void setUniversity(List<University> university) {
        this.university = university;
    }

    @Override
    public String toString() {
        return "UniversityList [university=" + university + "]";
    }
}

class University{

    private String title;
    private String country;

    public University() {
    }

    public University(String title, String country) {
        super();
        this.title = title;
        this.country = country;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getCountry() {
        return country;
    }

    public void setCountry(String country) {
        this.country = country;
    }

    @Override
    public String toString() {
        return "University [title=" + title + ", country=" + country + "]";
    }

Как получить значения "Заголовок" и "Страна"? Я не уверен, почему он вернул нулевые значения. Любая помощь будет оценена. Спасибо.

Ответы [ 2 ]

1 голос
/ 17 апреля 2020

Джексон отображает свойства по имени !

Некоторые советы Java Guy помогут решить проблему путем изменения имени вложенного ArrayList от university до data (аналогично соответствующему массиву в JSON).

java.lang.NullPointerException (NPE) выбрасывается при попытке получить список из объекта root.

Проблема: что случилось?

1. Допустимый шаблон считывателя:

Вы отключили DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES Это говорит Джексону о десериализации допустимого JSON в объект, даже если некоторые из его содержимого не может быть отображено.

Без отключения этого (настройка по умолчанию) Джексон бы сгенерировал исключение (JsonMappingException) здесь, так как JSON свойство data не может быть сопоставлено ни с одним из свойств класса UniversityList.

2. Свойства не были сопоставлены, все остаются null:

Объект list создан (с использованием конструктора default / no-args ). Но поскольку его свойство ArrayList university не было ни инициализировано, ни установлено (отображено) Джексоном, оно остается null.

3. NPE, брошенный при доступе:

Как только ваш для l oop попытается получить доступ к свойству через list.getUniversity(), NPE выбрасывается.

Предотвращение NPE: Защитное кодирование

Всегда следите за тем, чтобы используемый вами объект (ссылка) был не нулевым , здесь:

if (list != null && list.getUniversity() != null) {
  // now below for loop is safe (no NPE)
  for (University u : list.getUniversity()) {
      // do something with u
  }
}

Кроме того, обычно это хорошая практика инициализировать списки, даже если они пусты. Например, в вашем классе UniversityList объявите:

List<University> university = new ArrayList<>();

Обращайтесь с осторожностью: особенности Джексона

Хотя используемый DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES будет действовать как Джокер здесь, позволяя Джексону читать JSON, даже если отображение не подходит, вам следует обратить особое внимание и проверить возвращаемые значения . См. Аналогичный вопрос: { ссылка }

Определить сопоставление Джексона

Либо использовать сопоставление Джексона по умолчанию по имени : Java Имя свойства объекта должно быть то же как в JSON. Или используйте аннотации @JsonProperty, чтобы определить JSON имя , если оно отклоняется от Java Имя объекта.

В вашем случае это будет:

@JsonProperty("data")
List<University> university = new ArrayList<>();

Настройка Джексона

Джексон предлагает множество аннотаций, позволяющих выполнить настройку. См. Статья Баэльдуна .

Таким образом, вы можете заменить глобально отключенного DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES на аннотацию класса c:

@JsonIgnoreProperties(ignoreUnknown = true)
public class UniversityList {
  // body removed
}
1 голос
/ 17 апреля 2020

Я подозреваю, что если вы измените имя

private List<University> university;

public List<University> getUniversity() {
    return university;
}

public void setUniversity(List<University> university) {
    this.university = university;
}

на что-то более похожее на

private List<University> data;

public List<University> getData() {
    return data;
}

public void setData(List<University> data) {
    this.data = data;
}

, оно будет заполнено. Вы также можете использовать аннотации, чтобы сказать Джексону: «Эй,« данные »означают мой список университетов» -:).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...