REST Assured POJO and Serialization & Deserialization
Hand-written JSON strings are fine for one test and painful for a hundred. POJOs let you build request bodies and read responses as normal Java objects, while REST Assured converts between Java and JSON for you. This guide covers POJOs, serialization and deserialization, nested objects and lists, the Jackson annotations you'll actually need, and the errors you'll run into.
What Is a POJO?
A POJO (Plain Old Java Object) is a simple class with private fields, getters and setters, and a no-argument constructor — no framework base class required. In API testing, a POJO models a request or response body:
public class User {
private String name;
private String email;
private int age;
public User() {} // needed for deserialization
public User(String name, String email, int age) {
this.name = name;
this.email = email;
this.age = age;
}
public String getName() { return name; }
public String getEmail() { return email; }
public int getAge() { return age; }
public void setName(String name) { this.name = name; }
public void setEmail(String email) { this.email = email; }
public void setAge(int age) { this.age = age; }
}
Interview answer:
"A POJO is a plain Java class with private fields, getters, setters and a default constructor. In REST Assured I use POJOs as request payloads and to map JSON responses to Java objects, which makes tests type-safe and easier to maintain than raw JSON strings."
Why Use POJOs?
| Manual JSON strings | POJOs |
|---|---|
| Typos and missing quotes break requests | The compiler catches mistakes |
| Hard to change one field per test | Set one field with a setter or builder |
| Painful for large or nested payloads | Nested objects and lists are natural |
| Values read with JSON paths as strings | Values read with typed getters |
| Little reuse | Shared models across many tests |
Serialization: Java Object → JSON
Serialization converts a Java object into JSON for the request body. REST Assured does it automatically when you pass an object to body() and a JSON library such as Jackson or Gson is on the classpath:
User user = new User("John", "john@test.com", 28);
given()
.contentType(ContentType.JSON)
.body(user) // serialized to JSON automatically
.when()
.post("/users")
.then()
.statusCode(201);
The request body sent:
{
"name": "John",
"email": "john@test.com",
"age": 28
}
If you need the JSON string itself — for logging or a file — serialize manually:
String json = new ObjectMapper().writeValueAsString(user); // Jackson
String json2 = new Gson().toJson(user); // Gson
Deserialization: JSON → Java Object
Deserialization converts a JSON response into a Java object, so you read values through getters instead of JSON paths:
User user = given()
.when()
.get("/users/101")
.then()
.statusCode(200)
.extract()
.as(User.class);
Assert.assertEquals(user.getName(), "John");
Assert.assertTrue(user.getEmail().endsWith("@test.com"));
Manual equivalents:
new ObjectMapper().readValue(body, User.class);
or:
new Gson().fromJson(body, User.class);
| Serialization | Deserialization | |
|---|---|---|
| Direction | Java object → JSON | JSON → Java object |
| Used for | Request payloads | Response handling |
| REST Assured | .body(user) |
.extract().as(User.class) |
Nested Objects and Lists
Real payloads are nested. Model each JSON object as its own class:
{
"orderId": 5001,
"customer": {
"name": "Asha",
"city": "Pune"
},
"items": [
{
"sku": "BOOK-1",
"qty": 2
},
{
"sku": "PEN-7",
"qty": 5
}
]
}
The corresponding Java models can look like this:
public class Order {
private int orderId;
private Customer customer;
private List<Item> items;
// getters, setters, no-arg constructor
}
public class Customer {
private String name;
private String city;
// getters, setters, no-arg constructor
}
public class Item {
private String sku;
private int qty;
// getters, setters, no-arg constructor
}
Deserialize the response:
Order order = when()
.get("/orders/5001")
.then()
.extract()
.as(Order.class);
Assert.assertEquals(order.getItems().size(), 2);
Assert.assertEquals(order.getCustomer().getCity(), "Pune");
When the Response Is a JSON Array
User[] users = when()
.get("/users")
.then()
.extract()
.as(User[].class);
Or for a list nested inside the response, such as { "data": [...] }:
List<User> list = when()
.get("/users")
.then()
.extract()
.jsonPath()
.getList("data", User.class);
Jackson Annotations You'll Actually Use
@JsonIgnoreProperties(ignoreUnknown = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class User {
@JsonProperty("first_name")
private String firstName;
// ...
}
@JsonIgnoreProperties(ignoreUnknown = true)— with Jackson's default settings, a response field that has no matching POJO field can make deserialization fail. This annotation (or a configuredObjectMapper) keeps tests stable when the API adds fields.@JsonProperty— maps snake_case or otherwise different JSON keys to Java names.@JsonInclude(NON_NULL)— builds partial payloads, for example for PATCH requests or negative tests with missing fields.
Less boilerplate: many teams generate getters, setters and builders with Lombok (@Data, @Builder, @NoArgsConstructor), or use Java records for read-only response models with recent Jackson versions.
Common Errors and Fixes
| Error | Cause | Fix |
|---|---|---|
"Cannot serialize object because no JSON serializer found in classpath" |
No Jackson or Gson dependency | Add jackson-databind (or Gson) to pom.xml |
UnrecognizedPropertyException |
Response has a field the POJO doesn't | @JsonIgnoreProperties(ignoreUnknown = true) |
"No suitable constructor" / cannot construct instance |
No no-argument constructor | Add a public no-arg constructor |
| Fields missing from the request JSON | No getters (Jackson serializes through getters) | Add getters, or annotate the fields |
| Wrong key names in the JSON | Java naming differs from the API's | @JsonProperty("api_name") |
Jackson vs Gson
| Jackson | Gson | |
|---|---|---|
| Maintained by | FasterXML | |
| REST Assured support | Yes — preferred when both are present | Yes |
| Annotations and configuration | Extensive (@JsonProperty, @JsonIgnoreProperties, @JsonInclude…) |
Simpler (@SerializedName, @Expose) |
| Typical choice | Most Java API frameworks | Simple projects, Android |
Best Practices
- Use one POJO per request or response model, preferably in a
modelspackage. - Keep field names aligned with the API contract; use
@JsonPropertywhere they differ. - Ignore unknown properties in response models so new API fields don't break tests.
- Use builders or factory methods for test data so each test changes only what it needs.
- Combine POJO assertions with JSON Schema Validation for contract checks.
See how requests are built and responses extracted step by step in the REST Assured Visualizer.
From Real Projects
My API experience covers CRUD operations, HTTP methods, JSON path, and validating JSON and XML responses, and my automation work was in Java with TestNG. That combination is exactly what REST Assured builds on: HTTP calls in Java, JSON path for extracting values, and TestNG for running and grouping the tests. If you already know Selenium with TestNG, REST Assured fits into the same project structure. Testsigma supports web, mobile and API test automation, so understanding APIs was part of understanding the product I was testing. POJOs make request bodies readable and reusable across tests. See also: Response Validation in REST Assured.
📚 Official documentation: REST Assured official site · MDN: HTTP
FAQs
What is a POJO class?
A Plain Old Java Object — a simple class with private fields, getters, setters and a no-argument constructor, used here to model request and response bodies.
What is serialization in REST Assured?
Serialization means converting a Java object to JSON for the request body. REST Assured does it automatically when you pass an object to .body() with a JSON content type and Jackson or Gson on the classpath.
What is deserialization?
Deserialization means converting a JSON response into a Java object, typically with .extract().as(User.class).
How do you deserialize a JSON array?
Use .extract().as(User[].class) for a top-level array, or jsonPath().getList("data", User.class) for a list inside the response.
Why does deserialization fail with "Unrecognized field"?
The response contains a field your POJO doesn't have. Add @JsonIgnoreProperties(ignoreUnknown = true) or configure the ObjectMapper to ignore unknown properties.
Jackson or Gson?
Jackson is the common choice for Java API frameworks because of its annotations and configuration; Gson is simpler. REST Assured supports both.