REST Assured - Generic List deserialization

JavaArraysJsonDeserializationRest Assured

Java Problem Overview


Let's say I have a Java Person class:

class Person {
    String name;
    String email;
}

With REST Assured, you can deserialize this JSON object

{"name":"Bob", "email":"[email protected]"} 

to a Java Person instance using

Person bob = given().when().get("person/Bob/").as(Person.class);

How does one use REST Assured to deserialize this JSON array

[{"name":"Bob", "email":"[email protected]"}, 
 {"name":"Alice", "email":"[email protected]"}, 
 {"name":"Jay", "email":"[email protected]"}]

into a List<Person>? For example, this would be handy:

List<Person> persons = given().when().get("person/").as(...);

Java Solutions


Solution 1 - Java

I found a way to achieve what I wanted:

List<Person> persons = given().when().get("person/").as(Person[].class);

UPDATE: Using Rest-Assured 1.8.1, looks like cast to List is not supported anymore. You need to declare and object array like this:

Person[] persons = given().when().get("person/").as(Person[].class);

Solution 2 - Java

To extract a Java List, and not an Array, from a JSON API response, you just have to remember to use jsonPath rather than as:

List<Person> persons = given()
        .when()
        .get("/person")
        .then()
        .extract()
        .body()
        // here's the magic
        .jsonPath().getList(".", Person.class);

Your json path can point to anywhere you expect to have a list of json objects in your body. in this example (and working for your question) it just points to the json root.

sidenode: rest-assured is internally using jackson for deserialization (for .jsonPath as well as .as)

Solution 3 - Java

for those who found out that accepted answer does not work anymore.

    List<Entity> list = new ArrayList<>();
	list = given()
			.contentType(CONTENT_TYPE)
		.when()
			.get(getRestOperationPath())
		.then()
			.extract().body().as(list.getClass());
	

hopefully, you understand that getRestOperationPath is returning rest operation path; and CONTENT_TYPE is placeholder for your content type (application/json for example)

upd: checked different versions, behavior differs depending on version, so you might want to try different approaches

upd2: cleaner solution was pointed by @Arigion in comments:

to use .extract().body().jsonPath().getList(".", Entity.class);
	

Solution 4 - Java

You could also do this if you were interested in using "expect()"

expect().
 body("get(0).firstName", equalTo("Mike")).
when().
 get("person/");

This was my case

Solution 5 - Java

We can now use TypeRef much as it's possible to do it with the JsonPath library:

List<Person> persons = given().when().get("person/")
    .as(new TypeRef<List<Person>>() {});

As with https://github.com/json-path/JsonPath#what-is-returned-when - the anonymous inner class new TypeRef<List<Person>>() {} gets around type erasure and captures the type information enough that the framework can access the raw type - List in this case. The internal generic type - Person - is a safe cast that can be made under the circumstances.

Solution 6 - Java

If anyone's still looking. Using Java 1.8 and RestAssured 2.9 the solution is really simple and it does not throw "Unchecked Warning".

return Arrays.asList(given()
			.when()
			.get("restPath")
			.then()
			.extract()
			.response()
			.body()
			.as(Player[].class));

Solution 7 - Java

If you are not comfortable with JsonPath, i would suggest using any java serialization/de-serialization using GSON or Jackson.

Solution 8 - Java

This would be helpful, works with current version of rest assured.

@Test
    public void apostUser() {
        Map<String,String> user = new HashMap<>();
        user.put("User_Id", "xyx1111");
        user.put("First_Name", "KS");
        user.put("Designation", "DR");

        given()
        .contentType("application/json")
        .body(user)
        .when().post("URI").then()
        .statusCode(200);
    }

Solution 9 - Java

Since you want to map

[{"name":"Bob", "email":"[email protected]"}, 
 {"name":"Alice", "email":"[email protected]"}, 
 {"name":"Jay", "email":"[email protected]"}]

to java object.

Now while calling the endpoint you can directly map to the Person list as shown below

List<Person> personList = given().when().get("person/").as(Person[].class);

Note the Person class should remain same i.e. no need to do any modification for the person class.

public class Person{
 String name;
 String email;
}


Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionspgView Question on Stackoverflow
Solution 1 - JavaspgView Answer on Stackoverflow
Solution 2 - JavaChristian DrägerView Answer on Stackoverflow
Solution 3 - JavaAndrii PlotnikovView Answer on Stackoverflow
Solution 4 - Javaallegjdm93View Answer on Stackoverflow
Solution 5 - JavaAshley FriezeView Answer on Stackoverflow
Solution 6 - JavaKristijan RusuView Answer on Stackoverflow
Solution 7 - JavaKshetra Mohan PrustyView Answer on Stackoverflow
Solution 8 - JavakrishnaView Answer on Stackoverflow
Solution 9 - JavaVikas KumarView Answer on Stackoverflow