Как мне вернуть List‹Object› из JSON, как это?

Я делаю веб-приложение, используя Giant Bomb API.

Я застрял, потому что мне нужно получить список результатов поиска из запроса GET (используя Unirest), а затем удобно преобразовать его в список объектов, называемых предложениями.

Вот где моя проблема:

private List<Suggestion> suggestions = new ArrayList<>();

public List<Suggestion> searchGames(){

    HttpResponse<String> request;
    try {
    request = Unirest.get("http://giantbomb.com/api/search/?api_key=xxxxxxxxxxxxxxxxxxxxxxxxx&format=json&resources=game&limit=10&field_list=name&query=creed")
                .header("Accept", "application/json")
                .asString();

    String requestString = request.toString(); //I can get my request as String, but that doesnt change much, I guess

    //>>> the problematic part <<<

    return suggestions;
}

Мне не хватает чего-то, что позволило бы мне преобразовать ответ JSON из Unirest в список. Вот что я пробовал:

  • GSON - проблемы с форматом JSON (в начале JSON есть данные из-за полей с Limit, Offset и т.д.)
  • Object Mapper (Unirest/Jackson) — проблемы, так как я получаю httpResponse вместо String/Object/JsonNode и т. д.
  • используя JSONObject, JSONArray и цикл for - тоже не повезло.

Мой вызов JSON от Unirest выглядит примерно так:

 {
        "error": "OK",
        "limit": 10,
        "offset": 0,
        "number_of_page_results": 1,
        "number_of_total_results": 3,
        "status_code": 1,
        "results": [
            {
                "name": "Assassin's Creed",
                "resource_type": "game"
            },
            {
                "name": "The Creed",
                "resource_type": "game"
            },
            {
                "name": "Assassin's Creed: Lost Legacy",
                "resource_type": "game"
            }
        ]
}

У меня есть аналогичное решение для класса Game, где я отображаю список с именами games.

private List<Game> games = new ArrayList<>();

public List<Game> getAllGames(){
    return games;
}

Я заполняю этот список, используя запросы GET, где я ввожу идентификатор и заголовок.

Предложения, поступающие от Giant Bomb API, для меня сложнее, поскольку я использую внешний API для получения списка объектов вместо ввода входных данных.

Мой класс Suggestion.java выглядит так:

package rest.library;


public class Suggestion {

    private long id;
    private String name;

    public Suggestion(){
    }

    public Suggestion(long id, String name) {
        this.id = id;
        this.name = name;
    }

    public long getId() {
        return id;
    }

    public String getName() {
        return name;
    }

}

В моем контроллере я хочу сделать это:

@RequestMapping("/search")
public List<Suggestion> searchGames() { return gameService.searchGames(); }

Переход под localhost:8080/search должен вернуть список объектов с результатами поиска, полученными из запроса JSON. Он должен выглядеть так же, как localhost:8080/games, который возвращает мне список игр, отправленных с помощью GET на Postman. Я знаю, что я получаю поле "resource_type" из API, а поля "id" нет, но это проблема на потом, так как я думаю, что заполнение выбранных полей класса и постепенное добавление идентификатора не будет такой большой проблемой.


person VapeKop    schedule 13.07.2017    source источник
comment
stackoverflow.com/questions/17037340/   -  person Harish Pathak    schedule 13.07.2017
comment
Это для ArrayList‹String› (я получаю ошибки с несовместимыми типами), и я не знаю, как преобразовать запрос (httpResponse‹Object/JsonNode/String›, например, в JSONArray.   -  person VapeKop    schedule 13.07.2017
comment
JSONObject myObject = новый JSONObject (результат);   -  person Harish Pathak    schedule 13.07.2017
comment
stackoverflow.com/ вопросы/18073849/   -  person Harish Pathak    schedule 13.07.2017
comment
Джексон может скрыть ваш ответ непосредственно от вашей модели, вы тоже можете это попробовать.   -  person Harish Pathak    schedule 13.07.2017
comment
org.json.JSONException: JSONObject[результаты] не найден. Пробовал делать первые две ссылки: JSONObject›JSONArray›ArrayLIST. org.json.JSONException: JSONObject[результаты] не найден. Здесь что-то не так: ` //JSONOBJECT›JSONARRAY JSONObject myObj = new JSONObject(request.getBody().getObject()); JSONArray jsonArray = myObj.getJSONArray(результаты); `   -  person VapeKop    schedule 13.07.2017


Ответы (2)


Что вам нужно, так это способ сопоставить объект String, полученный вами по вашему запросу, с HashMap, чтобы вы могли затем установить атрибуты вашего объекта и сформировать список для возврата (даже несмотря на то, что существуют API-интерфейсы, такие как Jackson, которые реализуют обработку запросов REST логика гораздо менее болезненная).

Это означает, что сначала нужно получить InputStream из HTTP-запроса с помощью response.getEntity().getContent(), а затем создать JSONParser, как указано здесь.

Это позволит вам получить атрибуты из строки JSON, как показано здесь.

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

Дайте мне знать, помогло ли это вообще.

person Austin Schäfer    schedule 13.07.2017
comment
Это здорово, я посмотрю на это как можно скорее. Насколько проще было бы с Джексоном? Я имею в виду, я пытался, но были и проблемы. - person VapeKop; 13.07.2017
comment
Я использую Jackson на своем рабочем месте, и как только он настроен, это довольно просто. Вы создаете метод ресурса с аннотацией @GET, аннотацией @Path(PATH_HERE) и добавляете параметры (любого типа) к методу, которые представляют, что принимает тело метода и/или путь. Этого должно быть достаточно для автоматического преобразования тела запроса JSON в указанный POJO. - person Austin Schäfer; 13.07.2017
comment
Еще один вопрос относительно вашего ответа. Почему request.getEntity().getContent() сообщает мне, что getEntity() не может быть разрешен? - person VapeKop; 13.07.2017
comment
Я не уверен, не видя вашего текущего кода. Создайте еще один вопрос с вашим текущим кодом, и я посмотрю, смогу ли я понять это. - person Austin Schäfer; 13.07.2017
comment
Неважно, кажется, что getEntity должен быть вне метода try, но поскольку я инициализирую запрос inputStream AFTER инициализируется ... Это кажется неразрешимым конфликтом. - person VapeKop; 13.07.2017
comment
Это может быть вариант, когда ваш метод выдает любые типы исключений, которые вам нужно поймать, что позволит вам избавиться от блока try. Это, или вы можете просто оставить одну строку внутри блока try и поместить остальные снаружи. - person Austin Schäfer; 13.07.2017
comment
и то, и другое не работает - если я попытаюсь поймать исключение, то getEntity() не сможет быть снова разрешен. если я попытаюсь сохранить InputStream снаружи, у меня еще не будет инициализирован «запрос». Кажется, это полный круг ошибок. Мне не придется иметь дело с Hashmaps, если я решу переключиться на Джексона, верно? Кажется, это единственный рациональный путь сейчас для меня, а. - person VapeKop; 13.07.2017
comment
Правильно, вы будете иметь дело со своим POJO вместо HashMaps. Просто не забудьте правильно отформатировать входящую строку JSON! (Также рекомендуется использовать аннотацию @JsonIgnoreProperties(ignoreUnknown = true) над вашим классом POJO. Это должно помешать неизвестному вводу испортить ваш день. - person Austin Schäfer; 17.07.2017
comment
Проблема, с которой я столкнулся, также была связана с моим ответом JSON, который не заключал скобки {} в мой ответ, если было более 10 результатов. Я использовал другой внешний API с более удобным ответом JSON, а затем сопоставление через Джексона сработало как шарм. - person VapeKop; 17.07.2017

Я рекомендую использовать https://github.com/jsunsoftware/http-request, построенный на apache http api. Вы можете создать класс ResponseData для анализа ответа.

 private static final HttpRequest<ResponseData> HTTP_REQUEST = 
        HttpRequestBuilder.createGet("http://giantbomb.com/api/search", ResponseData.class)
        .addDefaultHeader("Accept", "application/json")
        .addDefaultRequestParameter("api_key", "xxxxxxxxxxxxxxxxxxxxxxxxx")
        .addDefaultRequestParameter("format", "json")
        .addDefaultRequestParameter("resources", "game")
        .addDefaultRequestParameter("limit", "10")
        .addDefaultRequestParameter("field_list", "name")
        .addDefaultRequestParameter("query", "creed")
        .build();

  List<Suggestion> searchGames() {
      ResponseHandler<ResponseData> responseHandler = HTTP_REQUEST.execute();
      ResponseData responseData = responseHandler.get();

      // Here create the List<Suggestion> from responseData   

      return suggestions
  }

private class ResponseData{
    private String error;
    private int limit;
    private int offset;
    private int number_of_page_results;
    private int number_of_total_results;
    private int status_code;
    private List<Result> results;

    //getters and setters
}

private class Result{
    private String name;
    private String resource_type;

    //getters and setters
}
person Beno Arakelyan    schedule 21.09.2017