- Back to Home »
- JAX-RS , RESTful , web service »
- Building RESTful WS with JAX-RS (Jersey) and Tomcat
This post is dedicated to my friend jagdish salgotra who wanted me to write something on RESTful web services and to all starters in this area.
In the REST(REpresentational State Transfer) world, information on the server side is considered a resource, which anyone can access in a uniform way using web URIs (Uniform Resource Identifiers) and HTTP. Because REST uses HTTP as the communication protocol, the REST style is constrained to a stateless client/server architecture. We can map the HTTP methods POST, GET, PUT, and DELETE to create, read, update and delete (CRUD) operations.
There are many ways to write RESTful web services:
> Sun offers a reference implementation for JAX-RS code-named Jersey.
> Spring provides RestTemplate for the same purpose
In this sample example (very basic and naive just to give u all a gentle kick) I will try to explain how we can use DEPARTMENT as representational state in REST using GET method. We will try to map following urls to the particular state we are interested in using Jersey implementation.
/api/departments/ | Get all departments |
/api/departments/{id} | Get details of a particular department |
/api/departments/employees | Get all departments with employee details |
/api/departments/{id}/employees | Get employees of particular department |
NOTE: All employees related data will be available under department node (by design)
The output of the Restful web services can be a plain text, html, xml, json or any media type, For our example We will use XML as content type of our service output and will rely on JAXB annotations to provide the required marshaling/unmarshaling services.
Let's start with the root XML element. I chose to call mine GetDepartmentResponse, and use it as a container for a collection of Department objects. This is just to do with the convention I usually follow (no hard fast rules behind this).
package com.mg.rest.hr.resources; import java.util.ArrayList; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class GetDepartmentResponse { private List<Department> departments; @XmlElement(name = "department") @XmlElementWrapper(name = "departments") public List<Department> getAllDepartments() { if (departments == null) { departments = new ArrayList<Department>(); } return departments; } }
Notice the @XmlElementWrapper annotation on the Department collection. This makes JAXB wrap all of the department XML elements inside of an departments XML element. Also notice that I placed the @XmlElement annotations on the getter methods instead of on the private fields. When placed on the private fields, JAXB will give you an error unless you add @XmlAccessorType(XmlAccessType.FIELD) at the class level.
Next we define our Resources - Department and Employee
package com.mg.rest.hr.resources; import java.util.List; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElementWrapper; import javax.xml.bind.annotation.XmlType; /** * * @author Munish Gogna * */ @XmlType(name = "department") public class Department { private String deptId; private String deptName; private List<Employee> employees; public Department() { } @XmlElement public String getDeptId() { return deptId; } @XmlElement(name = "employee") @XmlElementWrapper(name = "employees") public List<Employee> getEmployees() { return employees; } @XmlElement public String getDeptName() { return deptName; } public void setDeptId(String deptId) { this.deptId = deptId; } public void setEmployees(List<Employee> employees) { this.employees = employees; } public void setDeptName(String deptName) { this.deptName = deptName; } }In the example above, we use @XmlType at the class level instead of @XmlRootElement because it is not the root element
package com.mg.rest.hr.resources; import java.math.BigDecimal; import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlType; /** * * @author Munish Gogna * */ @XmlType(propOrder = { "empId", "empName", "salary" }) public class Employee { private String empId; private String empName; private BigDecimal salary; public Employee() { } public Employee(String empId, String empName, BigDecimal salary) { super(); this.empId = empId; this.empName = empName; this.salary = salary; } @XmlElement public BigDecimal getSalary() { return salary; } @XmlElement public String getEmpId() { return empId; } @XmlElement public String getEmpName() { return empName; } public void setEmpId(String empId) { this.empId = empId; } public void setEmpName(String empName) { this.empName = empName; } public void setSalary(BigDecimal salary) { this.salary = salary; } }
Now lets create a JAX-RS RESTful web service that can return above defined object graph in the responses we have defined in the beginning of this article.
JAX-RS defines a resource as any Java class (POJO) that uses JAX-RS annotations to implement a web resource. The annotation @Path identifies a Java class as a resource class as shown below.
package com.mg.rest.hr; import javax.ws.rs.GET; import javax.ws.rs.Path; import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import com.mg.rest.hr.resources.Department; import com.mg.rest.hr.resources.GetDepartmentResponse; /** * Service to handle Department and related resources. * Just a mock implementation, nothing fancy. * @author Munish Gogna * */ @Path("/api") public class DepartmentResource { @GET @Produces("text/xml") @Path("/departments/employees") public GetDepartmentResponse getAllDepartmentsWithEmployees() { GetDepartmentResponse response = new GetDepartmentResponse(); response.getAllDepartments().addAll( FromHeaven.getDeptsWithEmps().values()); return response; } @GET @Produces("text/xml") @Path("/departments/{id}") public GetDepartmentResponse getDepartment(@PathParam("id") String id) { GetDepartmentResponse response = new GetDepartmentResponse(); Department dept = FromHeaven.getDepts().get(id); response.getAllDepartments().add(dept); return response; } @GET @Produces("text/xml") @Path("/departments/{id}/employees") public GetDepartmentResponse getEmployeesForDepartment( @PathParam("id") String id) { GetDepartmentResponse response = new GetDepartmentResponse(); Department dept = FromHeaven.getDeptsWithEmps().get(id); response.getAllDepartments().add(dept); return response; } @GET @Produces("text/xml") @Path("/departments") public GetDepartmentResponse getAllDepartments() { GetDepartmentResponse response = new GetDepartmentResponse(); response.getAllDepartments().addAll(FromHeaven.getDepts().values()); return response; } }
Notice the @Produces("text/xml") annotation, and that the method returns a GetDepartmentResponse object. Since the GetDepartmentResponse is annotated with JAXB annotations, JAX-RS will automatically marshal the response to XML.
Also note that FromHeaven is a utility class that provides dummy departmental data(This class has 2 hard coded departments D1 and D2 with 2 employees in D1 and only single employee in D2)
Let's try some URIs now:
1. http://localhost:8080/rest/api/departments
D2 Human Resource D1 Finance
2. http://localhost:8080/rest/api/departments/D1
D1 Finance
3. http://localhost:8080/rest/api/departments/employees
D1 Finance e1 Munish Gogna 1000 e2 Jagdish Salgotra 2000 D2 Human Resource e3 Sahil Gogna 5000
4.http://localhost:8080/rest/api/departments/D1/employees
D1 Finance e1 Munish Gogna 1000 e2 Jagdish Salgotra 2000
In order for Jersey to work, we need to configure the JAX-RS Servlet in the web.xml as shown below:
com.mg.rest.hr JAX-RS REST Servlet com.sun.jersey.spi.container.servlet.ServletContainer com.sun.jersey.config.property.packages com.mg.rest.hr 1 JAX-RS REST Servlet /*
Notice that we have to provide the package name (com.mg.rest.hr) of the resource handler classes to the servlet class.
That's all for now, later some day we will try make these RESTful services secure so that only authorized callers can use these resources.
Please don't forget to provide your valuable feedback, especially you Jagi :)
Hi, thanks for this, cool stuff. Would it be too much asking if you could link the source code in a .zip file?
ReplyDeleteHi Macluq can you please pass me your email Id so that I can send you the same?
ReplyDeleteThanks Munish for such a nice article and work. This was really helpful in understanding the REST api. Please keep on doing good work and help novice like me.
ReplyDeleteThanks once again.Could you please mail me code also.
Have you implemented JAX-RS 2.0 ?
ReplyDeleteSunil, the article was based on 1.x
DeleteThank you very much for providing the nice article.
ReplyDeleteI was eхcіted to uncover this web site.
ReplyDeleteI wаnt tο to thank yоu for уour
tіme јust for this fantaѕtiс reaԁ!!
I ԁefinitely really liκed every bit оf
it and i alsο have yοu book-marked to ѕee new things оn уоur webѕite.
mу site - Rеad the Full Соntent ()