1

I am working on Rest assured framework to automate API testing. actually I want to get the response as list not as an object. cause I want to do assertions for each element. to check data integrity for each element. I am executing this code:

    List<Category> categories = given().
            headers(
                    "Authorization",
                    "Bearer key",
                    "Content-Type",
                    ContentType.JSON,
                    "Accept",
                    ContentType.JSON)
            .when()
            .get("/rest/V1/categories").then().extract().response().jsonPath().getList("", Category.class);

This is the Category Class:

public class Category  {

private Long id = null;

private Long parent_id = null;

private String name = null;

private boolean is_active = true;

private int position = 0;

private int level = 0;

private int product_count = 0;

private ArrayList<Category> children_data = null;

public Long getId() {
    return id;
}
public void setId(Long id) {
    this.id = id;
}

public Long getParent_id() {
    return parent_id;
}
public void setParent_id(Long parent_id) {
    this.parent_id = parent_id;
}

/**
 **/
public Boolean getIs_active() {
    return is_active;
}
public void setIs_active(Boolean is_active) {
    this.is_active = is_active;
}

/**
 **/
public String getName() {
    return name;
}
public void setName(String name) {
    this.name = name;
}

/**
 **/
public int getProduct_count() {
    return product_count;
}
public void setProduct_count(int product_count) {
    this.product_count = product_count;
}

public int getLevel() {
    return level;
}
public void setLevel(int level) {
    this.level = level;
}

public int getPosition() {
    return position;
}
public void setPosition(int position) {
    this.position = position;
}

/**
 **/
public List<Category> getChildren_data() {
    return children_data;
}
public void setChildren_data(List<Category> children_data) {
    this.children_data = children_data;
}

This is the console log:

java.lang.ClassCastException: class java.util.HashMap cannot be cast to class java.util.List (java.util.HashMap and java.util.List are in module java.base of loader 'bootstrap')

My Json raw:

{ "id": 2, "parent_id": 1, "name": "Default Category", "is_active": true, "position": 1, "level": 1, "product_count": 2046, "children_data": [ { "id": 38, "parent_id": 2, "name": "What's New", "is_active": true, "position": 1, "level": 2, "product_count": 0, "children_data": [] }, { "id": 20, "parent_id": 2, "name": "Women", "is_active": true, "position": 2, "level": 2, "product_count": 1012, "children_data": [ { "id": 21, "parent_id": 20, "name": "Tops", "is_active": true, "position": 1, "level": 3, "product_count": 784, "children_data": [ { "id": 23, "parent_id": 21, "name": "Jackets", "is_active": true, "position": 1, "level": 4, "product_count": 186, "children_data": [] }, { "id": 24, "parent_id": 21, "name": "Hoodies & Sweatshirts", "is_active": true, "position": 2, "level": 4, "product_count": 182, "children_data": [] }, { "id": 25, "parent_id": 21, "name": "Tees", "is_active": true, "position": 3, "level": 4, "product_count": 192, "children_data": [] }, { "id": 26, "parent_id": 21, "name": "Bras & Tanks", "is_active": true, "position": 4, "level": 4, "product_count": 224, "children_data": [] } ] }, { "id": 22, "parent_id": 20, "name": "Bottoms", "is_active": true, "position": 2, "level": 3, "product_count": 228, "children_data": [ { "id": 27, "parent_id": 22, "name": "Pants", "is_active": true, "position": 1, "level": 4, "product_count": 91, "children_data": [] }, { "id": 28, "parent_id": 22, "name": "Shorts", "is_active": true, "position": 2, "level": 4, "product_count": 137, "children_data": [] } ] } ] }, { "id": 11, "parent_id": 2, "name": "Men", "is_active": true, "position": 3, "level": 2, "product_count": 982, "children_data": [ { "id": 12, "parent_id": 11, "name": "Tops", "is_active": true, "position": 1, "level": 3, "product_count": 678, "children_data": [ { "id": 14, "parent_id": 12, "name": "Jackets", "is_active": true, "position": 1, "level": 4, "product_count": 176, "children_data": [] }, { "id": 15, "parent_id": 12, "name": "Hoodies & Sweatshirts", "is_active": true, "position": 2, "level": 4, "product_count": 208, "children_data": [] }, { "id": 16, "parent_id": 12, "name": "Tees", "is_active": true, "position": 3, "level": 4, "product_count": 192, "children_data": [] }, { "id": 17, "parent_id": 12, "name": "Tanks", "is_active": true, "position": 4, "level": 4, "product_count": 102, "children_data": [] } ] }, { "id": 13, "parent_id": 11, "name": "Bottoms", "is_active": true, "position": 2, "level": 3, "product_count": 304, "children_data": [ { "id": 18, "parent_id": 13, "name": "Pants", "is_active": true, "position": 1, "level": 4, "product_count": 156, "children_data": [] }, { "id": 19, "parent_id": 13, "name": "Shorts", "is_active": true, "position": 2, "level": 4, "product_count": 148, "children_data": [] } ] } ] }, { "id": 3, "parent_id": 2, "name": "Gear", "is_active": true, "position": 4, "level": 2, "product_count": 46, "children_data": [ { "id": 4, "parent_id": 3, "name": "Bags", "is_active": true, "position": 1, "level": 3, "product_count": 14, "children_data": [] }, { "id": 5, "parent_id": 3, "name": "Fitness Equipment", "is_active": true, "position": 2, "level": 3, "product_count": 23, "children_data": [] }, { "id": 6, "parent_id": 3, "name": "Watches", "is_active": true, "position": 3, "level": 3, "product_count": 9, "children_data": [] } ] }, { "id": 9, "parent_id": 2, "name": "Training", "is_active": true, "position": 5, "level": 2, "product_count": 6, "children_data": [ { "id": 10, "parent_id": 9, "name": "Video Download", "is_active": true, "position": 1, "level": 3, "product_count": 6, "children_data": [] } ] }, { "id": 7, "parent_id": 2, "name": "Collections", "is_active": false, "position": 5, "level": 2, "product_count": 989, "children_data": [ { "id": 8, "parent_id": 7, "name": "New Luma Yoga Collection", "is_active": true, "position": 1, "level": 3, "product_count": 347, "children_data": [] }, { "id": 34, "parent_id": 7, "name": "Erin Recommends", "is_active": true, "position": 2, "level": 3, "product_count": 279, "children_data": [] }, { "id": 35, "parent_id": 7, "name": "Performance Fabrics", "is_active": true, "position": 3, "level": 3, "product_count": 310, "children_data": [] }, { "id": 36, "parent_id": 7, "name": "Eco Friendly", "is_active": true, "position": 4, "level": 3, "product_count": 247, "children_data": [] }, { "id": 39, "parent_id": 7, "name": "Performance Sportswear New", "is_active": true, "position": 5, "level": 3, "product_count": 0, "children_data": [] }, { "id": 40, "parent_id": 7, "name": "Eco Collection New", "is_active": true, "position": 6, "level": 3, "product_count": 0, "children_data": [] } ] }, { "id": 29, "parent_id": 2, "name": "Promotions", "is_active": false, "position": 6, "level": 2, "product_count": 654, "children_data": [ { "id": 30, "parent_id": 29, "name": "Women Sale", "is_active": true, "position": 1, "level": 3, "product_count": 224, "children_data": [] }, { "id": 31, "parent_id": 29, "name": "Men Sale", "is_active": true, "position": 2, "level": 3, "product_count": 39, "children_data": [] }, { "id": 32, "parent_id": 29, "name": "Pants", "is_active": true, "position": 3, "level": 3, "product_count": 247, "children_data": [] }, { "id": 33, "parent_id": 29, "name": "Tees", "is_active": true, "position": 4, "level": 3, "product_count": 192, "children_data": [] } ] }, { "id": 37, "parent_id": 2, "name": "Sale", "is_active": true, "position": 6, "level": 2, "product_count": 0, "children_data": [] } ] }

user3669148
  • 43
  • 1
  • 2
  • 8
  • 1
    Can you get how does your raw JSON looks like and add it to the question? – chef417 Jun 10 '20 at 00:07
  • @chef417 Json raw has been added, thanks – user3669148 Jun 10 '20 at 00:23
  • Your JSON seems invalid - I tried copying it to online JSON editors and it reports invalid, e.g. try here: https://jsoneditoronline.org/#left=local.qaqola&right=local.qecuzu .. Just from glancing, you seem to have 6 opened square brackets `[` and 3 closed ones `]`, which tells me the problem is probably the invalid JSON – chef417 Jun 10 '20 at 00:44
  • @chef417 json provided is in the correct format. – Sara Jun 10 '20 at 05:40
  • @user3669148 try private List children_data = null; and edit getters/setters accordingly – Sara Jun 10 '20 at 05:44
  • @user3669148 also, try sending various test data. e.g., "children_data":null and only one set in "children_data" – Sara Jun 10 '20 at 05:46
  • 1
    @user3669148 - Try adding `private Category[] children_data;` in Category class. And change the getters and setters. And also, try chaging getList() method to `.getList("$", Category.class);` You will get a List with a single item. and all other `children_data` will be in the (Category type) array in that item. If you want to skip the initial object (`"name": "Default Category"`) and get all other `children_data` to List, then change getList() method to `.getList("children_data", Category.class);` – kaweesha Jun 10 '20 at 06:14
  • You want to get a `List<>` using `getList()` method but your JSON doesn't start with List. Instead of `getList` use `get` and it will work. – Fenio Jun 10 '20 at 06:54
  • @kaweesha I think you can write the answer to the question – Fenio Jun 10 '20 at 06:54
  • @Sara same error – user3669148 Jun 10 '20 at 08:28
  • @kaweesha I got the same problem – user3669148 Jun 10 '20 at 08:28
  • @Fenio I got this error: "class java.util.HashMap cannot be cast to class [Ldataentities.Category;" – user3669148 Jun 10 '20 at 08:32
  • @user3669148 Yes, sorry. The method is `getObject()` not `get()`. Cheers! – Fenio Jun 10 '20 at 08:36
  • @Fenio I got this error: "com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `dataentities.Category` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)" – user3669148 Jun 10 '20 at 08:53
  • @user3669148 Great! Let me write the answer cause we just solved the issue – Fenio Jun 10 '20 at 08:53
  • @Fenio What about the current error – user3669148 Jun 10 '20 at 08:55
  • @user3669148 Will be in the answer – Fenio Jun 10 '20 at 08:55
  • @user3669148 Check out my answer and comment there with problems not stated in the question – Fenio Jun 10 '20 at 08:59
  • @Fenio do you mean something like this: .getObject("", List); – user3669148 Jun 10 '20 at 09:11
  • Let me update the answer – Fenio Jun 10 '20 at 09:12
  • @user3669148 Check edited answer – Fenio Jun 10 '20 at 09:13
  • @kaweesha actually I want to get the response as list not as an object. cause I want to do assertions for each element. to check data integrity for each element – user3669148 Jun 10 '20 at 11:35

3 Answers3

1

You want to get a List<> using getList() method but your JSON doesn't start with List. Instead of getList use getObject and it will work. getObject() maps the JSON to POJO class of your choice.

While deserializing JSON, you might encounter below issue

com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of dataentities.Category (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

All you need to do is add a dependency to tell Rest-Assured which deserializer you want to use. My personal choice is:

<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.9.9</version>
</dependency>

EDIT: To deserialize JSON into a POJO you use getObject() method like this:

Category category = jsonPath.getObject("", Category.class);

EDIT: You should make your Category class fields public OR create setters and getters. Otherwise, there will be exceptions.

Fenio
  • 3,528
  • 1
  • 13
  • 27
  • Hey Fenio, Been following this question and a +1 for the answer but how do we get the values of children_data ? `categories.getId()` works and returns 2 but how do we get ID 38 ? – Wilfred Clement Jun 10 '20 at 09:09
  • 1
    @WilfredClement The simplest solution is `category.children_data.get(0).id` – Fenio Jun 10 '20 at 09:16
  • @WilfredClement I suppose you would like to know a solution using a specific approach? – Fenio Jun 10 '20 at 09:23
  • I'd be happy to see if there is one, I just used `categories.getChildren_data().get(0).getId()` for the time being – Wilfred Clement Jun 10 '20 at 09:26
  • @Fenio I got this error: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `dataentities.Category` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: (String)" – user3669148 Jun 10 '20 at 09:28
  • @user3669148 You should make your Category class fields public OR create setters and getters. Otherwise, there will be exceptions. – Fenio Jun 10 '20 at 09:33
  • @Fenio I have setters and getters – user3669148 Jun 10 '20 at 09:36
  • @user3669148 I don't see it them in the question. Update your question then. – Fenio Jun 10 '20 at 09:50
  • @WilfredClement How about `System.out.println(JsonPath.from(json).getObject("children_data.find { it.id == 38 }", Category.class).id);`? :) – Fenio Jun 10 '20 at 10:00
  • Isn't that the data type of `children_data` should be `Category[]`? – kaweesha Jun 10 '20 at 10:09
  • @kaweesha Lists are supported – Fenio Jun 10 '20 at 10:10
  • @user3669148 Why didn't you put that information in the question? Which list do you want to transform with POJO? Where are the setters and getters of Category class? – Fenio Jun 10 '20 at 11:10
  • @Fenio actually I want to get the response as the list not as the object. cause I want to do assertions for each element. to check data integrity for each element. but by your solution, I cannot make that – user3669148 Jun 10 '20 at 11:36
  • @user3669148 You have the desired list `children_data` variable. Or you can use `List categories = Arrays.asList(jsonpath.getObject("children_data", Category[].class));` Also, read about POJO deserialization with Jackson. You need to annotate getters and setters with `@JsonProperty`. And yes, you can check all fields with my solution because `Category` class contains everything you have in the JSON provided. – Fenio Jun 10 '20 at 11:37
  • @user3669148 Stackoverflow's comment section is not the best place to chat or discuss good practices unless related to the solution. If I answer your question, kindly mark it as the accepted answer. If you have any questions NOT related to this question - file a new one OR visit my profile and contact me on Skype – Fenio Jun 10 '20 at 11:44
0

In your category class;

change private ArrayList<Category> children_data = null;

to private List<Category> children_data = null;

And try to execute with;

.getList("children_data", Category.class);

This should work.

kaweesha
  • 803
  • 6
  • 16
0

You can use Gson library for converting your json response into POJO

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.5</version>
</dependency>

Then use this statement to get the expected array of categories.

Response response = given()
        .headers("Authorization","Bearer key",
                 "Content-Type",ContentType.JSON,
                 "Accept",ContentType.JSON)
        .get("/rest/V1/categories");

Category[] categories = new Gson().fromJson(response.getBody().asString(),Category[].class);

Now Assert on categories or you may need to have a list, then Do this,

List<Category> categoryList = Arrays.asList(categories);