Till now we
developed following REST APIs.
API URL
|
Method
|
Description
|
/employees
|
GET
|
Return all
employees
|
/employees
|
POST
|
Add new
employee
|
/employees/employeeID
|
GET
|
Get
employee details for given id
|
/employees/employeeID
|
PUT
|
Update
specific employee
|
/employees/employeeID
|
DELETE
|
Delete
employee details for given id
|
/employees?city=Bangalore
|
GET
|
Get all employees
staying at Bangalore
|
/employees?start=1&size=2
|
GET
|
Get all
employees with ids 1, 2 and 3
|
/employees/1/address/permanentAddress
|
GET
|
Get
Permanent address of employee 1.
|
/employees/1/address/temporaryAddress
|
GET
|
Get
Temporary address of employee 1.
|
As you
observe, I didn’t implement any exception handling mechanism for above apis. In
this post, I am going to explain how to implement exception handling mechanism-using
Jersey.
My Task is,
suppose Rest client asks for an employee, who doesn’t exist, I need to throw
error message in JSON format.
{
errorCode:201
message: Given id 4 not exist
}
It is 2 step
process.
1.
First
need to build custom exception class.
public class DataNotFoundException extends
RuntimeException {
.......
.......
}
2.
Create
a mapper class, which registers custom exception with jersey.
@Provider
public class DataNotFoundExceptionMapper implements
ExceptionMapper<DataNotFoundException>
{
.....
.....
.....
}
By using
Provider annotation, we can register this class to JAX-RX, during JAX-RS
runtime provider scanning phase.
That’s it,
whenever you written custom exception, jersey throws error message in json
format.
Following is
the step-by-step procedure to build complete application.
Step 1: Create package “com.jersey_tutorial.model” to
store all model classes.
Step 2: Create
model classes Employee, Address.
Address.java
package com.jersey_tutorial.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Address { private String street; private String city; private String state; private String country; public Address() { this("No Data", "No Data", "No Data", "No Data"); } public Address(String area, String city, String state, String country) { super(); this.street = area; this.city = city; this.state = state; this.country = country; } public String getArea() { return street; } public String getCity() { return city; } public String getCountry() { return country; } public String getState() { return state; } public void setArea(String area) { this.street = area; } public void setCity(String city) { this.city = city; } public void setCountry(String country) { this.country = country; } public void setState(String state) { this.state = state; } }
Employee.java
package com.jersey_tutorial.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Employee { private String firstName; private String lastName; private long id; private Address permAddrees; private Address tempAddrees; public Employee() { this("No Data", "No Data", -1, new Address(), new Address()); } public Employee(String firstName, String lastName, long id, Address permAddrees, Address tempAddrees) { super(); this.firstName = firstName; this.lastName = lastName; this.id = id; this.permAddrees = permAddrees; this.tempAddrees = tempAddrees; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; } public long getId() { return id; } public void setId(long id) { this.id = id; } public Address getPermAddrees() { return permAddrees; } public void setPermAddrees(Address permAddrees) { this.permAddrees = permAddrees; } public Address getTempAddrees() { return tempAddrees; } public void setTempAddrees(Address tempAddrees) { this.tempAddrees = tempAddrees; } }
XmlRootElement
annotation is used to map a Java class to an XML element.
Create
ErrorMessage class to send Error information to client.
package com.jersey_tutorial.model; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class ErrorMessage { private int errorCode; private String errorMessage; public ErrorMessage(int errorCode, String errorMessage) { super(); this.errorCode = errorCode; this.errorMessage = errorMessage; } public ErrorMessage() { super(); } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public String getErrorMessage() { return errorMessage; } public void setErrorMessage(String errorMessage) { this.errorMessage = errorMessage; } }
Step 3: Create Exception and mapper classes. Create package com.jersey_tutorial.exception.
Create DataNotFoundException
class.
package com.jersey_tutorial.exception; public class DataNotFoundException extends RuntimeException { private int errorCode; private String message; public DataNotFoundException() { super(); } public DataNotFoundException(int errorCode, String message) { this.errorCode = errorCode; this.message = message; } public int getErrorCode() { return errorCode; } public void setErrorCode(int errorCode) { this.errorCode = errorCode; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } }
Create DataNotFoundExceptionMapper
class.
package com.jersey_tutorial.exception; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.ext.ExceptionMapper; import javax.ws.rs.ext.Provider; import com.jersey_tutorial.model.ErrorMessage; @Provider public class DataNotFoundExceptionMapper implements ExceptionMapper<DataNotFoundException> { @Override public Response toResponse(DataNotFoundException ex) { ErrorMessage model = new ErrorMessage(ex.getErrorCode(), ex.getMessage()); return Response.status(Status.NOT_FOUND).entity(model).build(); } }
Step 4: Create EmployeeService class.
package com.jersey_tutorial.services; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.TreeMap; import com.jersey_tutorial.exception.DataNotFoundException; import com.jersey_tutorial.model.Address; import com.jersey_tutorial.model.Employee; public class EmployeeService { private static TreeMap<Long, Employee> employees = new TreeMap<>(); static { initializeEmployees(); } private static void initializeEmployees() { Address tempAddr1 = new Address("Electronic City", "Bangalore", "Karnataka", "India"); Address tempAddr2 = new Address("BTM Layout", "Bangalore", "Karnataka", "India"); Address tempAddr3 = new Address("SR Nagar", "Hyderabad", "Andhra Pradesh", "India"); Address permAddr1 = new Address("Marthali", "Bangalore", "Karnataka", "India"); Address permAddr2 = new Address("Bharath Nagar", "Hyderabad", "Andhra Pradesh", "India"); Address permAddr3 = new Address("Bharath Nagar", "Hyderabad", "Andhra Pradesh", "India"); Employee emp1 = new Employee("Hari Krishna", "Gurram", 1, permAddr1, tempAddr1); Employee emp2 = new Employee("PTR", "PTR", 2, permAddr2, tempAddr2); Employee emp3 = new Employee("Rama Krishna", "Gurram", 3, permAddr3, tempAddr3); employees.put(1l, emp1); employees.put(2l, emp2); employees.put(3l, emp3); } public static Map<Long, Employee> getAllEmployees() { return employees; } public static List<Employee> getEmployeesForCity(String city) { List<Employee> employeesForCity = new ArrayList<>(); for (Employee emp : employees.values()) { if (emp.getPermAddrees().getCity().equals(city) || emp.getTempAddrees().getCity().equals(city)) { employeesForCity.add(emp); } } return employeesForCity; } public static List<Employee> getEmployeesPaginated(long start, long size) { return new ArrayList<>(employees .subMap(start, true, start + size, true).values()); } public static Employee getEmployee(long id) { Employee emp = employees.get(id); if (emp == null) throw new DataNotFoundException(1, "Employee with id " + id + " Not exist"); return emp; } public static Employee addEmployee(Employee emp) { long newId = employees.size() + 1; emp.setId(newId); employees.put(newId, emp); return emp; } public static Employee updateEmployee(long id, Employee emp) { emp.setId(id); employees.put(id, emp); return emp; } public static Employee deleteEmployee(long empId) { Employee emp = employees.get(empId); employees.remove(empId); return emp; } }
Step 5: Create EmployeeResource and AddressResource
classes.
package com.jersey_tutorial.resources; import java.net.URI; import java.util.ArrayList; import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.PUT; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.UriInfo; import com.jersey_tutorial.model.Employee; import com.jersey_tutorial.services.EmployeeService; @Path("employees") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class EmployeeResource { @GET public List<Employee> getAllEmployees(@QueryParam("city") String city, @QueryParam("start") long start, @QueryParam("size") long size) { if (city != null) return EmployeeService.getEmployeesForCity(city); if (start > 0 && size > -1) return EmployeeService.getEmployeesPaginated(start, size); return new ArrayList<>(EmployeeService.getAllEmployees().values()); } @GET @Path("/{employeeId}") public Employee getEmployee(@PathParam("employeeId") long empId) { return EmployeeService.getEmployee(empId); } @POST public Response addEmployee(Employee emp, @Context UriInfo uriInfo) { Employee employee = EmployeeService.addEmployee(emp); String empId = String.valueOf(employee.getId()); URI uri = uriInfo.getAbsolutePathBuilder().path(empId).build(); return Response.status(Status.CREATED).entity(employee) .header("new_url", uri.toString()).build(); } @PUT @Path("/{employeeId}") public Employee updateEmployee(@PathParam("employeeId") long empId, Employee emp) { return EmployeeService.updateEmployee(empId, emp); } @DELETE @Path("/{employeeId}") public Employee removeEmployee(@PathParam("employeeId") long empId) { return EmployeeService.deleteEmployee(empId); } @Path("/{employeeId}/address") public AddressResource getAddress() { AddressResource resource = new AddressResource(); System.out.println("Hello"); return resource; } }
Create AddressResource class.
package com.jersey_tutorial.resources; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import com.jersey_tutorial.model.Address; import com.jersey_tutorial.services.EmployeeService; public class AddressResource { @GET @Path("/temporaryAddress") public Address getTempAddress(@PathParam("employeeId") long empId) { return EmployeeService.getEmployee(empId).getTempAddrees(); } @GET @Path("/permanentAddress") public Address getPermAddress(@PathParam("employeeId") long empId) { return EmployeeService.getEmployee(empId).getPermAddrees(); } }
Following is
the web.xml file.
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0"> <display-name>jersey_tutorial</display-name> <welcome-file-list> <welcome-file>index.html</welcome-file> <welcome-file>index.htm</welcome-file> <welcome-file>index.jsp</welcome-file> <welcome-file>default.html</welcome-file> <welcome-file>default.htm</welcome-file> <welcome-file>default.jsp</welcome-file> </welcome-file-list> <servlet> <servlet-name>Jersey REST Service</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>jersey.config.server.provider.packages</param-name> <param-value>com.jersey_tutorial.resources, com.jersey_tutorial.exception</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name> <url-pattern>/*</url-pattern> </servlet-mapping> </web-app>
Following are
the dependencies I used.
<dependencies> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet-core</artifactId> <version>2.21</version> </dependency> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-server</artifactId> <version>2.21</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-moxy</artifactId> <version>2.21</version> </dependency> </dependencies>
Run
application on server.
Now if you
try to access any employee who doesn’t exist, you will get JSON error message.
If you hit
following url.
You will get
following error message.
{"errorCode":1,"errorMessage":"Employee
with id 5 Not exist"}
Following is
the complete project structure.
No comments:
Post a Comment