Будьте уверены - десериализуйте ответ JSON в виде списка ‹POJO›

У меня есть POJO Artwork. Я получаю List этих объектов из веб-службы RESTful в теле ответа HTTP в формате JSON. Я пытаюсь написать тест на основе Rest Assured, который проанализирует возвращенный список. Код выглядит так:

Response response = get("/artwork");
List returnedArtworks = response.getBody().as(List.class)

Проблема в том, что я не могу заставить Rest Assured проанализировать возвращенный JSON как List<Artwork>. Вместо этого я получаю List<LinkedHashMap>. Карта имеет правильную структуру, т.е. может быть сопоставлена ​​Джексоном с объектом Artwork, но я бы не хотел отображать ее вручную.

Сопоставления JSON в моей модели в порядке, потому что когда я сопоставляю один объект следующим образом:

Artwork returnedArtwork = response.getBody().as(Artwork.class);

работает нормально.

Возможно ли получить returnedArtworks как List<Artwork>?


person Wojtek    schedule 12.02.2014    source источник
comment
Ответил на ваш вопрос ниже ..   -  person Purushotham    schedule 13.02.2014


Ответы (5)


Ты можешь сделать это:

List<Artwork> returnedArtworks = Arrays.asList(response.getBody().as(Artwork[].class));

Уловка состоит в том, чтобы десериализовать JSON в массив объектов (поскольку нет разницы между строкой JSON массива или списка), а затем преобразовать массив в список.

person volatilevar    schedule 03.08.2014
comment
Вы должны добавить объяснение к решению для других, кто это найдет. - person Ian Stapleton Cordasco; 03.08.2014
comment
Спасибо, я добавил краткое пояснение (и исправил ошибку). - person volatilevar; 03.08.2014
comment
Не могу проверить это прямо сейчас, но, предполагая, что все положительные отзывы исходят от пользователей, которые сочли это решение полезным, я отмечаю это как принятый ответ. - person Wojtek; 07.04.2017
comment
Я поддержал этот ответ, поскольку он краток. Но у меня это не работает. Я два часа пытался это исправить, но получаю такую ​​ошибку: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of ................. - person Jose4Linux; 04.06.2020

это решение работает для версии 3.0.2 (io.restassured):

  JsonPath jsonPath = RestAssured.given()
     .when()
     .get("/order")
     .then()
     .assertThat()
     .statusCode(Response.Status.OK.getStatusCode())
     .assertThat()
     .extract().body().jsonPath();

  List<Order> orders = jsonPath.getList("", Order.class);

Это позволит извлечь объекты для такой структуры:

public class Order {

private String id;

public String getId(){
return id; }

public void setId(String id){
this.id = id;
}


}

с данным json:

[ 
{ "id" : "5" }, 
{ "id" : "6" }
]
person Seren    schedule 29.03.2017

Используя библиотеку Google Gson, вы можете легко разобрать ее на List<Artwork>. Попробуйте под кодом

Gson gson = new Gson();
List<Artwork> returnedArtworks = gson.fromJson(jsonStr, new TypeToken<List<Artwork>>(){}.getType());

//* where jsonStr is the response string(Json) receiving from your Restful webservice
person Purushotham    schedule 12.02.2014
comment
Спасибо за ответ. Хотя это именно то, чего я хотел избежать: карта имеет правильную структуру, то есть может быть сопоставлена ​​Джексоном с объектом Artwork, но я бы хотел избежать сопоставления ее вручную. Я подумал, есть ли шанс сделать это примерно так: List<Artwork> returnedArtworks = response.getBody().asListOf(Artwork.class) - person Wojtek; 13.02.2014
comment
Если ваш класс Artwork точно совпадает с картой, которую вы получаете в ответ, вы можете использовать Gson вместо Jackson. Вы можете повторно использовать один и тот же класс Artwork. - person Purushotham; 13.02.2014
comment
На самом деле не имеет большого значения, использую ли я Гсона или Джексона. В любом случае мне пришлось бы написать дополнительную строку кода для анализа полученной в ответ карты. Я надеялся, что в Rest Assured это каким-то образом реализовано, поскольку довольно часто в ответ мы получаем List объектов. - person Wojtek; 13.02.2014
comment
TypeToken#getType() можно использовать непосредственно как параметр в .as() гарантированного покоя. См. Мой ответ: stackoverflow.com/a/57373937/91497 - person Jmini; 06.08.2019

Будьте уверены, предоставьте _ 1_ рядом с версией, ожидающей Class, использованной в вопросе.

java.lang.reflect.Type type; //TODO defines the type.
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)

На мой взгляд, способ, которым переменная type зависит от используемой библиотеки сериализации.


При использовании Gson, как указано в ответе Пурушотама, можно использовать TypeToken. Я предпочитаю использовать его непосредственно в спокойном:

Type type = new TypeToken<List<Artwork>>(){}.getType();
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)

При использовании Джексона решением является использование TypeFactory (javadoc, source), чтобы указать, к какому типу следует десериализовать:

Type type = TypeFactory.defaultInstance().constructCollectionLikeType(ArrayList.class, Artwork.class);
Response response = get("/artwork");
List<Artwork> returnedArtworks = response.getBody().as(type)
person Jmini    schedule 06.08.2019

С REST Assured 3.0.2 вы можете просто проверить, существует ли контент в массиве.

when().get("/artwork").then().body("artworks", hasItem("some art");
//or check multiple values in array
when().get("/artwork").then().body("artworks", hasItems("some art", "other art");

Таким образом, вы избежите сложности в своем коде, преобразовав JSON в список дополнительных примеров, как проверить содержимое ответа можно найти ссылка

person Vytautas    schedule 05.05.2017