Overview:
This is Part 2 of the article on RESTful WS with Apache CXF. If you haven't looked at Part 1, I suggest you to do so.
This article looks at how you can do JSON/HTTP based RESTful WS with Apache CXF. We're using the CXF support on JAX-RS (JSR-311) for this. The sample code can be found here.
Prerequisite:JDK >= 1.5.x
Project Structure: Following is the project structure I have used (Maven WAR project).
Step 1: Maven Dependencies (pom.xml)
Step 2: Creating POJO Classes and Service Implementation
Employee.java
Employees.java - This is used to hold a collection object of Employee.java
IEmployeeService.java - Service Interface
EmployeeService.java - Implementation of the service.
Read more about Apache CXF - JAX-RS basics.
Step 3: Exposing the Service Beans as RESTful Web Service
Step 4: Updating the web.xml to Register the CXF Servlet.
mvn clean install
Step 6: Deploying the Service
Now you can deploy this service on to any container. Here we'll deploy this on Tomcat server.
Step 7: Testing the RESTful Web Service using CURL
We're going to test our Web Service using CURL, which I found as a very easy way to send REST Calls. I found this very nice blog about RESTing with Curl.
Installing CURL
sudo apt-get install curl
-I am using Ubuntu, if you're using Win or Mac, please do the necessary to install curl.
Now, after successfully installing CURL, we are ready to test the services.
GET Resources:
- Retrieving all the employee resources.
- Retrieving a employee resource for a given id(id = 1).
POST a Resource: Adding a new employee resource.
- Adding the new employee record in the add.json file.
PUT a Resource: Updating an existing employee resource.
- Updating an existing employee record in the update.json file.
DELETE a Resource: Deleting an employee for a given id (id=2)
Summary:
This tutorial looked at how we can create JSON RESTful Web Service using Apache CXF and test the services using CURL. You can find the sample code here.
This is Part 2 of the article on RESTful WS with Apache CXF. If you haven't looked at Part 1, I suggest you to do so.
This article looks at how you can do JSON/HTTP based RESTful WS with Apache CXF. We're using the CXF support on JAX-RS (JSR-311) for this. The sample code can be found here.
Prerequisite:JDK >= 1.5.x
Maven >= 2.2.x
Project Structure: Following is the project structure I have used (Maven WAR project).
Step 1: Maven Dependencies (pom.xml)
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.fazlan</groupId>
<artifactId>org.fazlan.employee.cxf.jsonrest.service</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>org.fazlan.employee.cxf.jsonrest.service</name>
<url>http://maven.apache.org</url>
<build>
<finalName>CXFEmployeeJsonRESTService</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<!-- Spring framework -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${org.springframework.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-databinding-aegis</artifactId>
<!-- 2.4.4 or 2.5.0 -->
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
<properties>
<org.springframework.version>3.1.1.RELEASE</org.springframework.version>
<cxf.version>2.4.6</cxf.version>
</properties>
</project>
Step 2: Creating POJO Classes and Service Implementation
Employee.java
package org.fazlan.employee.cxf.jsonrest.service.beans;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.io.Serializable;
@XmlType(
name = "EmployeeType",
namespace = "org.fazlan.employee.cxf.jsonrest.service.beans",
propOrder = {"id", "firstName", "lastName"})
@XmlRootElement(
name = "Employee",
namespace = "org.fazlan.employee.cxf.jsonrest.service.beans")
public class Employee implements Serializable {
private Long id;
private String firstName;
private String lastName;
public Employee() {
}
public Employee(Long id, String firstName, String lastName) {
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
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 boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Employee)) return false;
Employee employee = (Employee) o;
return !(firstName != null ? !firstName.equals(employee.firstName) : employee.firstName != null) &&
!(id != null ? !id.equals(employee.id) : employee.id != null) &&
!(lastName != null ? !lastName.equals(employee.lastName) : employee.lastName != null);
}
public int hashCode() {
int result = id != null ? id.hashCode() : 0;
result = 31 * result + (firstName != null ? firstName.hashCode() : 0);
result = 31 * result + (lastName != null ? lastName.hashCode() : 0);
return result;
}
@Override
public String toString() {
return "Employee{" +
"id=" + id +
", firstName='" + firstName + '\'' +
", lastName='" + lastName + '\'' +
'}';
}
}
Employees.java - This is used to hold a collection object of Employee.java
package org.fazlan.employee.cxf.jsonrest.service.beans;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import java.util.Collection;
@XmlType(
name = "EmployeesType",
namespace = "org.fazlan.employee.cxf.jsonrest.service.beans")
@XmlRootElement(
name = "Employees",
namespace = "org.fazlan.employee.cxf.jsonrest.service.beans")
public class Employees {
private Collection<Employee> employees;
public Employees() {
}
public Employees(Collection<Employee> employees) {
setEmployees(employees);
}
@XmlElement(name = "employee",required = true)
@XmlElementWrapper(name = "employees")
public Collection<Employee> getEmployees() {
return employees;
}
public void setEmployees(Collection<Employee> employees) {
this.employees = employees;
}
}
IEmployeeService.java - Service Interface
package org.fazlan.employee.cxf.jsonrest.service.services;
import org.fazlan.employee.cxf.jsonrest.service.beans.Employee;
import org.fazlan.employee.cxf.jsonrest.service.beans.Employees;
import javax.ws.rs.core.Response;
public interface IEmployeeService {
Employee get(Long id);
Employees getAll();
Response add(Employee employee);
Response update(Employee employee);
Response delete(Long id);
}
EmployeeService.java - Implementation of the service.
NOTE: This service class has been annotated to produce and consume certain methods in JSON(application/json) as the mime-type. Read more about Apache CXF - JAX-RS basics.
package org.fazlan.employee.cxf.jsonrest.service.services;
import org.fazlan.employee.cxf.jsonrest.service.beans.Employee;
import org.fazlan.employee.cxf.jsonrest.service.beans.Employees;
import javax.ws.rs.*;
import javax.ws.rs.core.Response;
import java.util.HashMap;
import java.util.Map;
@Path("/employeeservice/")
@Produces("application/json")
public class EmployeeService implements IEmployeeService {
private static final Map<Long, Employee> EMPLOYEE_MAP = new HashMap<Long, Employee>();
private static long index = 3L;
static {
EMPLOYEE_MAP.put(1L, new Employee(1L, "First Name 1", "Last Name 1"));
EMPLOYEE_MAP.put(2L, new Employee(2L, "First Name 2", "Last Name 2"));
}
@GET
@Path("/get/{id}")
public Employee get(@PathParam("id") Long id) {
return EMPLOYEE_MAP.get(id);
}
@GET
@Path("/getall/")
public Employees getAll() {
return new Employees(EMPLOYEE_MAP.values());
}
@POST
@Path("/add/")
@Consumes("application/json")
public Response add(Employee employee) {
System.out.println("Adding :" + employee);
employee.setId(index++);
update(employee);
return Response.status(Response.Status.OK).build();
}
@PUT
@Path("/update/")
@Consumes("application/json")
public Response update(Employee employee) {
System.out.println("Updating :" + employee);
EMPLOYEE_MAP.put(employee.getId(), employee);
return Response.status(Response.Status.OK).build();
}
@DELETE
@Path("/delete/{id}/")
public Response delete(@PathParam("id") Long id) {
Employee e = EMPLOYEE_MAP.remove(id);
System.out.println("Deleted :" + e);
return Response.status(Response.Status.OK).build();
}
}
Read more about Apache CXF - JAX-RS basics.
Step 3: Exposing the Service Beans as RESTful Web Service
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jaxrs="http://cxf.apache.org/jaxrs"
xmlns:cxf="http://cxf.apache.org/core"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://cxf.apache.org/jaxrs
http://cxf.apache.org/schemas/jaxrs.xsd
http://cxf.apache.org/core
http://cxf.apache.org/schemas/core.xsd">
<!-- do not use import statements if CXFServlet init parameters link to this beans.xml -->
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-servlet.xml"/>
<jaxrs:server id="employeeService" address="/">
<jaxrs:serviceBeans>
<ref bean="employeeServiceBean"/>
</jaxrs:serviceBeans>
<jaxrs:extensionMappings>
<entry key="xml" value="application/xml" />
<entry key="json" value="application/json" />
</jaxrs:extensionMappings>
<jaxrs:features>
<cxf:logging/>
</jaxrs:features>
</jaxrs:server>
<bean id="employeeServiceBean" class="org.fazlan.employee.cxf.jsonrest.service.services.EmployeeService"/>
</beans>
Step 4: Updating the web.xml to Register the CXF Servlet.
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd" >
<web-app>
<display-name>CXF Web Service Web Application</display-name>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath*:spring/app-context.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<servlet>
<servlet-name>CXFServlet</servlet-name>
<servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>CXFServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Step 5: Building the Project mvn clean install
Step 6: Deploying the Service
Now you can deploy this service on to any container. Here we'll deploy this on Tomcat server.
Step 7: Testing the RESTful Web Service using CURL
We're going to test our Web Service using CURL, which I found as a very easy way to send REST Calls. I found this very nice blog about RESTing with Curl.
Installing CURL
sudo apt-get install curl
-I am using Ubuntu, if you're using Win or Mac, please do the necessary to install curl.
Now, after successfully installing CURL, we are ready to test the services.
GET Resources:
- Retrieving all the employee resources.
curl -v -H "Accept: application/json" http://localhost:8080/CXFEmployeeJsonRESTService/employeeservice/getall
- Retrieving a employee resource for a given id(id = 1).
curl -v -H "Accept: application/json" http://localhost:8080/CXFEmployeeJsonRESTService/employeeservice/get/1
POST a Resource: Adding a new employee resource.
- Adding the new employee record in the add.json file.
{
"ns1.Employee":{
"id":1,
"firstName":"First Name1",
"lastName":"Last Name1"
}
}
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X POST -d @add.json http://127.0.0.1:8080/CXFEmployeeJsonRESTService/employeeservice/add
- Updating an existing employee record in the update.json file.
{
"ns1.Employee":{
"id":1,
"firstName":"Updated First Name1",
"lastName" :"Updated Last Name1"
}
}
curl -v -H "Accept: application/json" -H "Content-type: application/json" -X PUT -d @update.json http://127.0.0.1:8080/CXFEmployeeJsonRESTService/employeeservice/update/
DELETE a Resource: Deleting an employee for a given id (id=2)
curl -i -H "Accept: application/json" -X DELETE http://localhost:8080/CXFEmployeeJsonRESTService/employeeservice/delete/2/
Summary:
This tutorial looked at how we can create JSON RESTful Web Service using Apache CXF and test the services using CURL. You can find the sample code here.
Hi there,
ReplyDeleteI have an REST/XML service. Now, I was told to expose another REST/JSON service in addition to REST/XML one.
But, I am getting Invalid JSON Namespace error. The XML Request/Response POJOs have a lot of Namespaces defined and I am only supposed to reuse them.
Could you please let me know if there is a way to do this?
I am attaching a part of my stacktrace for your reference.
Caused by: java.lang.IllegalStateException: Invalid JSON namespace: http://soaservices.webex.com/EnterpriseObjects/EBO/Subscription/V1
at org.codehaus.jettison.mapped.MappedNamespaceConvention.getJSONNamespace(MappedNamespaceConvention.java:182)
at org.codehaus.jettison.mapped.MappedNamespaceConvention.createKey(MappedNamespaceConvention.java:189)
at org.codehaus.jettison.mapped.MappedXMLStreamWriter.writeStartElement(MappedXMLStreamWriter.java:244)
Nice one. Thank you
ReplyDeleteI was able to deploy in Tomcat as you show this example , I am using windows , but I can't test it, is there any alternative using SOAP UI or other client service?
ReplyDeleteI'm working in windows. I can´t test with other tool like soap ui u other client rest? I've already deployed on tomcat . but I don't know how test the web service.
ReplyDeletebest regards
Firstly, if you simply wish to test the functionality of your code, then your Unit tests should be independent of frameworks - (read on Robert Martin a.k.a Uncle Bob's - Clean architecture). However, please not this article was not written with TDD(Test Driven Development) in mind - Nowhere near TDD.
DeleteTo answer your question, you can use JBoss RestEasy(http://www.jboss.org/resteasy).
Refer,
http://fazlansabar.blogspot.com.au/2012/12/restful-with-resteasy-part-14-client.html
and also, the prequel to the same article http://fazlansabar.blogspot.com.au/2012/12/restful-with-resteasy-part-14-creating.html
Cheers,
Fazlan
you have created 2 different example for XML and for Json, can we make this in Single file which accepts(produces/cosumes) both json and xml to gether?
ReplyDeleteCertainly! you can combine them into one.
Delete