Apache CXF Restful Web Service Example

In my previous tutorial we saw how to create a simple RESTful web service using Jersey. In this RESTful web service example we will create the same webservice using Apache CXF as JAX-RS implementation.

CXF supports the Java API for RESTful Web Services: JAX-RS 2.0 (JSR-339) and JAX-RS 1.1 (JSR-311). We will be using JAX-RS 1.1.

The advantage of following JAX-RS specification is that there is minimal to no code change when there is a need to change the provider. So the RESTful webservice code which we used for Jersey in the previous tutorial can be used as it is. Only the service startup and client needs to be changed based on provider specific implementation.

Project Description

  • In this RESTful webservice example, we create a simple Java Calculator class with operations ‘add’ and ‘subtract’.
  • We expose these as restful web services which accepts HTTP GET Requests and sends the response as XML or Plain Text.
  • The restful web service is made available at http://localhost:9999/calcrest/calc/add/ and http://localhost:9999/calcrest/calc/sub/
  • We send the parameters in the URI itself. For example, to add 20 and 30, the URI is, http://localhost:9999/calcrest/calc/add/20/30
  • We then create a web service client which sends a HTTP GET Request to the mentioned URI and the response (result of the invoked web service) is displayed.

Environment Used

Creating and Publishing Restful Web Service

  1. Create a Java Project ‘CalcJAXRSCXF’.
  2. In the Project Build Path add the required jars from the downloaded Apache CXF file. For the list of jar files to add, see the Project Structure (at the end of the post).
  3. Create a package ‘com.theopentutorials.jaxrs.calc’
  4. Create a Java class ‘CalcREST’ and type the following code.
    package com.theopentutorials.jaxrs.calc;
    
    import javax.ws.rs.GET;
    import javax.ws.rs.Path;
    import javax.ws.rs.PathParam;
    import javax.ws.rs.Produces;
    import javax.ws.rs.core.MediaType;
    
    @Path("/calc")
    public class CalcREST {
    
    	@GET
    	@Path("/add/{a}/{b}")
    	@Produces(MediaType.TEXT_PLAIN)
    	public String addPlainText(@PathParam("a") double a, @PathParam("b") double b) {
    		return (a + b) + "";
    	}
    	
    	@GET
    	@Path("/add/{a}/{b}")
    	@Produces(MediaType.TEXT_XML)
    	public String add(@PathParam("a") double a, @PathParam("b") double b) {
    		return "<?xml version=\"1.0\"?>" + "<result>" +  (a + b) + "</result>";
    	}
    	
    	@GET
    	@Path("/sub/{a}/{b}")
    	@Produces(MediaType.TEXT_PLAIN)
    	public String subPlainText(@PathParam("a") double a, @PathParam("b") double b) {
    		return (a - b) + "";
    	}
    	
    	@GET
    	@Path("/sub/{a}/{b}")
    	@Produces(MediaType.TEXT_XML)
    	public String sub(@PathParam("a") double a, @PathParam("b") double b) {
    		return "<?xml version=\"1.0\"?>" + "<result>" +  (a - b) + "</result>";
    	}
    }
    
  5. @Path may be used on classes and such classes are referred to as root resource classes. @PATH(“calc”) sets the path to the base URI + /calc. The base URI consists of the host, port and any context. We will set this base URI on creating the server.
  6. @Path may also be used on methods of root resource classes. This enables common functionality for a number of resources to be grouped together and potentially reused. So for example @PATH(“/add”) on the method signature indicates the URI path for this method to be invoked is base URI + /calc/add.
  7. To retrieve the parameters from the URI and get those values as variables, we use URI Path Templates which are variables enclosed within curly braces “{“ and “}” and are replaced at runtime to respond to a request based on the substituted URI. To obtain the value of the variable the @PathParam may be used on method parameter of a request method.
    • For example, for the relative URI /calc/add/20/30 with @Path(“/add/{a}/{b}”) and method signature String add(@PathParam(“a”) double a, @PathParam(“b”), the values 20 and 30 will be assigned to the variables a and b respectively.
  8. @GET annotation is used to indicate that the annotated method will be invoked in response to a HTTP GET request.
  9. @Produces annotation is used to specify the MIME media types of representations a resource can produce and send back to the client. In our example, our web service will produce representations identified by the MIME media type “text/plain” and “text/xml” which are specified using the static fields TEXT_PLAIN and TEXT_XML of MediaType class.
  10. Now we need to start a HTTP server to publish our web service and accept requests.
  11. Create a class “CalcRESTStartUp” and type the following code.
    package com.theopentutorials.jaxrs.calc;
    
    import org.apache.cxf.endpoint.Server;
    import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;
    import org.apache.cxf.jaxrs.lifecycle.SingletonResourceProvider;
    
    public class CalcRESTStartUp {
    
    	public static void main(String[] args) {
    		 JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
    	        sf.setResourceClasses(CalcREST.class);
    	        sf.setResourceProvider(CalcREST.class, 
    	            new SingletonResourceProvider(new CalcREST()));
    	        sf.setAddress("http://localhost:9999/calcrest/");
    	        Server server = sf.create();
    	        
    	        // destroy the server
    	        // uncomment when you want to close/destroy it
    	        // server.destroy();
    	        
    	}
    }
    
  12. We use the CXF’s “JAXRSServerFactoryBean” bean to help easily create server endpoints for JAX-RS at the mentioned BASE URI. Make sure that port number 9999 is not used by any other application. If so, use any other unused port.
  13. Run this class “CalcRESTStartup” as Java Application.
  14. Our class “CalcREST” should be identified as root resource class and should be deployed.
  15. To test it, open a browser and type the following URL

    http://localhost:9999/calcrest/calc?_wadl

    A Web Application Description Language (WADL) should be displayed.

  16. To test the service we can type the following URLs in the browser

    http://localhost:9999/calcrest/calc/add/20/30/

    and

    http://localhost:9999/calcrest/calc/sub/20/30/

  17. The output on the browser will be in XML format even though we have our service produce plain text. This is because of the accept type HTTP header sent by the browser. By default the browser sends the text/html accept type and other xhtml and xml types. Since our service does not accept html and seeing that the browser accepts XML, it produces the output in XML.

Creating a Restful Web Service Client

Let us access this web service programmatically by creating a client.

  1. Create a new package “com.theopentutorials.jaxrs.calc.client”.
  2. Create a new class “CalcRESTClient” in that package and type the following code.
    package com.theopentutorials.jaxrs.calc.client;
    
    import org.apache.cxf.jaxrs.client.WebClient;
    
    public class CalcRESTClient {
    	static final String REST_URI = "http://localhost:9999/calcrest/";
    	static final String ADD_PATH = "calc/add";
    	static final String SUB_PATH = "calc/sub";
    	static final String MUL_PATH = "calc/mul";
    	static final String DIV_PATH = "calc/div";
    	
    	public static void main(String[] args) {
    		int a = 122;
    		int b = 34;
    		String s = "";
    		
    		WebClient plainAddClient = WebClient.create(REST_URI);
    		plainAddClient.path(ADD_PATH).path(a + "/" + b).accept("text/plain");
    		s = plainAddClient.get(String.class);
    		System.out.println(s);
    		
    		WebClient xmlAddClient = WebClient.create(REST_URI);
    		xmlAddClient.path(ADD_PATH).path(a + "/" + b).accept("text/xml");
    		s = xmlAddClient.get(String.class);
    		System.out.println(s);
    		
    		WebClient plainSubClient = WebClient.create(REST_URI);
    		plainSubClient.path(SUB_PATH).path(a + "/" + b).accept("text/plain");
    		s = plainSubClient.get(String.class);
    		System.out.println(s);
    		
    		WebClient xmlSubClient = WebClient.create(REST_URI);
    		xmlSubClient.path(SUB_PATH).path(a + "/" + b).accept("text/xml");
    		s = xmlSubClient.get(String.class);
    		System.out.println(s);
    	}
    }
    
  3. In the client, we create a WebClient (CXF WebClient API) object based on the provided URI.
  4. We specify the “add” and “sub” resource paths and include parameters “a” and “b” to it.
  5. We also need to specify the accept type of the client request and HTTP method as GET by using the methods “accept” and “get”. The “get” method parameter specifies the format (String type) to convert the output.
  6. Add required jars to the classpath and run this client application. (See the Project Structure Referenced Libraries for the list of required jars.)

Output

156.0
<?xml version=”1.0″?><result>156.0</result>
88.0
<?xml version=”1.0″?><result>88.0</result>

Project Structure

Comments
  • Hugo T
    Reply

    Very easy to understand and follow, but I got an error after running: Exception in thread “main” java.lang.NoClassDefFoundError: javax/annotation/Resource

Leave a Comment

This site uses Akismet to reduce spam. Learn how your comment data is processed.