The Apache HTTP Client is a very robust library, suitable for both simple and advanced use cases when testing HTTP endpoints. Check out our guide covering basic request and response handling, as well as security, cookies, timeouts, and more:
Mocking is an essential part of unit testing, and the Mockito library makes it easy to write clean and intuitive unit tests for your Java code.
Get started with mocking and improve your application tests using our Mockito guide:
Handling concurrency in an application can be a tricky process with many potential pitfalls. A solid grasp of the fundamentals will go a long way to help minimize these issues.
Get started with understanding multi-threaded applications with our Java Concurrency guide:
Spring 5 added support for reactive programming with the Spring WebFlux module, which has been improved upon ever since. Get started with the Reactor project basics and reactive programming in Spring Boot:
Since its introduction in Java 8, the Stream API has become a staple of Java development. The basic operations like iterating, filtering, mapping sequences of elements are deceptively simple to use.
But these can also be overused and fall into some common pitfalls.
To get a better understanding on how Streams work and how to combine them with other language features, check out our guide to Java Streams:
Get started with Spring and Spring Boot, through the Learn Spring course:
>> LEARN SPRINGExplore Spring Boot 3 and Spring 6 in-depth through building a full REST API with the framework:
Yes, Spring Security can be complex, from the more advanced functionality within the Core to the deep OAuth support in the framework.
I built the security material as two full courses - Core and OAuth, to get practical with these more complex scenarios. We explore when and how to use each feature and code through it on the backing project.
You can explore the course here:
Spring Data JPA is a great way to handle the complexity of JPA with the powerful simplicity of Spring Boot.
Get started with Spring Data JPA through the guided reference course:
Refactor Java code safely β and automatically β with OpenRewrite.
Refactoring big codebases by hand is slow, risky, and easy to put off. Thatβs where OpenRewrite comes in. The open-source framework for large-scale, automated code transformations helps teams modernize safely and consistently.
Each month, the creators and maintainers of OpenRewrite at Moderne run live, hands-on training sessions β one for newcomers and one for experienced users. Youβll see how recipes work, how to apply them across projects, and how to modernize code with confidence.
Join the next session, bring your questions, and learn how to automate the kind of work that usually eats your sprint time.
1. Introduction
The RestTemplate class is the central tool for performing client-side HTTP operations in Spring. It provides several utility methods for building HTTP requests and handling responses.
And since RestTemplate integrates well with Jackson, it can serialize/deserialize most objects to and from JSON without much effort. However, working with collections of objects is not so straightforward.
In this tutorial, weβll learn how to use RestTemplate to GET and POST a list of objects.
Further reading:
Spring RestTemplate Error Handling
RestTemplate Post Request with JSON
2. Example Service
Weβll be using an employee API that has two HTTP endpoints, get all and create:
- GET /employees
- POST /employees
For communication between the client and server, weβll use a simple DTO to encapsulate basic employee data:
public class Employee {
public long id;
public String title;
// standard constructor and setters/getters
}
Now weβre ready to write code that uses RestTemplate to get and create lists of Employee objects.
3. Get a List of Objects With RestTemplate
Normally when calling GET, we can use one of the simplified methods in RestTemplate, such as:
getForObject(URI url, Class<T> responseType)
This sends a request to the specified URI using the GET verb, and converts the response body into the requested Java type. This works great for most classes, but it has a limitation; we canβt send lists of objects.
The problem is due to type erasure with Java generics. When the application is running, it has no knowledge of what type of object is in the list. This means the data in the list canβt be deserialized into the appropriate type.
Luckily, we have two options to get around this.
3.1. Using Arrays
First, we can use RestTemplate.getForEntity() to GET an array of objects via the responseType parameter. Whatever class we specify there will match ResponseEntityβs parameter type:
ResponseEntity<Employee[]> response =
restTemplate.getForEntity(
"http://localhost:8080/employees/",
Employee[].class);
Employee[] employees = response.getBody();
We could also have used RestTemplate.exchange to achieve the same result.
Note that the collaborator doing the heavy lifting here is ResponseExtractor, so if we need further customization, we can call execute and provide our own instance.
3.2. Using a Wrapper Class
Some APIs will return a top-level object that contains the list of employees instead of returning the list directly. To handle this situation, we can use a wrapper class that contains the list of employees.
public class EmployeeList {
private List<Employee> employees;
public EmployeeList() {
employees = new ArrayList<>();
}
// standard constructor and getter/setter
}
Now we can use the simpler getForObject() method to get the list of employees:
EmployeeList response = restTemplate.getForObject(
"http://localhost:8080/employees",
EmployeeList.class);
List<Employee> employees = response.getEmployees();
This code is much simpler, but requires an additional wrapper object.
4. Post a List of Objects With RestTemplate
Now letβs look at how to send a list of objects from our client to the server. Just like above, RestTemplate provides a simplified method for calling POST:
postForObject(URI url, Object request, Class<T> responseType)
This sends an HTTP POST to the given URI, with the optional request body, and converts the response into the specified type. Unlike the GET scenario above, we donβt have to worry about type erasure.
This is because now weβre going from Java objects to JSON. The list of objects and their type are known by the JVM, so theyβll be properly serialized:
List<Employee> newEmployees = new ArrayList<>();
newEmployees.add(new Employee(3, "Intern"));
newEmployees.add(new Employee(4, "CEO"));
restTemplate.postForObject(
"http://localhost:8080/employees/",
newEmployees,
ResponseEntity.class);
4.1. Using a Wrapper Class
If we need to use a wrapper class to be consistent with the GET scenario above, thatβs simple too. We can send a new list using RestTemplate:
List<Employee> newEmployees = new ArrayList<>();
newEmployees.add(new Employee(3, "Intern"));
newEmployees.add(new Employee(4, "CEO"));
restTemplate.postForObject(
"http://localhost:8080/employees",
new EmployeeList(newEmployees),
ResponseEntity.class);
5. Conclusion
Using RestTemplate is a simple way of building HTTP clients to communicate with our services.
It provides a number of methods for working with every HTTP method and simple objects. With a little bit of extra code, we can easily use it to work with lists of objects.
