Aug

07

REST Web Services with Apache CXF and Spring

Posted by : hopcroft | On : 07/08/2012

 In the next two post we are gonna to talk about how develop REST web services with java.  To that end we’re gonna use two different technologies, Apache CXF and Spring REST web services.

RESTful services with Apache CXF

Let’s start using Apache CXF. We have to create a simple Maven webapp project so that it’s easier to start with our basic example. Once we’ve created it, we have to define our domain object. We are going to create a Car.xsd file where we will define the normal attributes that a car may have, like brand, model, year or prize, …

After that we need to generate a Java domain object from it. We can achieve this through a simple method. We will create a Java class that will be responsible of generating that Java car object. You can see the code of this class below.

package com.hopcroft.example.cxf;

import com.sun.tools.xjc.XJCFacade;

public class Generator {
	public static void main(String[] args) throws Throwable {
		XJCFacade.main(new String[] {
			"-d", "src/main/java", "src/main/resources/car.xsd"	
		});
	}
}

 

As you can see we use the com.sun.tools.xjc.XJCFacade class to get the Car.xsd file where our Car definition exists. The Generator class will parse the XSD schema in order to create three new files:

  • Car.java. Our domain class that has javax annotations required to set the attributes of a car.
    //
    // Este archivo ha sido generado por la arquitectura JavaTM para la implantación de la referencia de enlace (JAXB) XML v2.2.5 
    // Visite <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
    // Todas las modificaciones realizadas en este archivo se perderán si se vuelve a compilar el esquema de origen. 
    // Generado el: PM.08.06 a las 08:03:40 PM CEST 
    //
    
    package com.hopcroft.example.car;
    
    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;
    import javax.xml.bind.annotation.XmlType;
    
    /**
     * <p>Clase Java para anonymous complex type.
     * 
     * <p>El siguiente fragmento de esquema especifica el contenido que se espera que haya en esta clase.
     * 
     * <pre>
     * &lt;complexType>
     *   &lt;complexContent>
     *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
     *       &lt;sequence>
     *         &lt;element name="brand" type="{http://www.w3.org/2001/XMLSchema}string"/>
     *         &lt;element name="model" type="{http://www.w3.org/2001/XMLSchema}string"/>
     *         &lt;element name="year" type="{http://www.w3.org/2001/XMLSchema}int"/>
     *         &lt;element name="prize" type="{http://www.w3.org/2001/XMLSchema}long"/>
     *       &lt;/sequence>
     *     &lt;/restriction>
     *   &lt;/complexContent>
     * &lt;/complexType>
     * </pre>
     * 
     * 
     */
    @XmlAccessorType(XmlAccessType.FIELD)
    @XmlType(name = "", propOrder = {
        "brand",
        "model",
        "year",
        "prize"
    })
    @XmlRootElement(name = "car")
    public class Car {
    
        @XmlElement(required = true)
        protected String brand;
        @XmlElement(required = true)
        protected String model;
        protected int year;
        protected long prize;
    
        /**
         * Obtiene el valor de la propiedad brand.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getBrand() {
            return brand;
        }
    
        /**
         * Define el valor de la propiedad brand.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setBrand(String value) {
            this.brand = value;
        }
    
        /**
         * Obtiene el valor de la propiedad model.
         * 
         * @return
         *     possible object is
         *     {@link String }
         *     
         */
        public String getModel() {
            return model;
        }
    
        /**
         * Define el valor de la propiedad model.
         * 
         * @param value
         *     allowed object is
         *     {@link String }
         *     
         */
        public void setModel(String value) {
            this.model = value;
        }
    
        /**
         * Obtiene el valor de la propiedad year.
         * 
         */
        public int getYear() {
            return year;
        }
    
        /**
         * Define el valor de la propiedad year.
         * 
         */
        public void setYear(int value) {
            this.year = value;
        }
    
        /**
         * Obtiene el valor de la propiedad prize.
         * 
         */
        public long getPrize() {
            return prize;
        }
    
        /**
         * Define el valor de la propiedad prize.
         * 
         */
        public void setPrize(long value) {
            this.prize = value;
        }
    
    }
  • ObjectFactory. java. A factory that is used to create new object from schema.
    //
    // Este archivo ha sido generado por la arquitectura JavaTM para la implantación de la referencia de enlace (JAXB) XML v2.2.5 
    // Visite <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
    // Todas las modificaciones realizadas en este archivo se perderán si se vuelve a compilar el esquema de origen. 
    // Generado el: PM.08.06 a las 08:03:40 PM CEST 
    //
    
    package com.hopcroft.example.car;
    
    import javax.xml.bind.annotation.XmlRegistry;
    
    /**
     * This object contains factory methods for each 
     * Java content interface and Java element interface 
     * generated in the com.hopcroft.example.car package. 
     * <p>An ObjectFactory allows you to programatically 
     * construct new instances of the Java representation 
     * for XML content. The Java representation of XML 
     * content can consist of schema derived interfaces 
     * and classes representing the binding of schema 
     * type definitions, element declarations and model 
     * groups.  Factory methods for each of these are 
     * provided in this class.
     * 
     */
    @XmlRegistry
    public class ObjectFactory {
    
        /**
         * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.hopcroft.example.car
         * 
         */
        public ObjectFactory() {
        }
    
        /**
         * Create an instance of {@link Car }
         * 
         */
        public Car createCar() {
            return new Car();
        }
    
    }
  • package-info.java. In this file we annotate the package of our car class.
    //
    // Este archivo ha sido generado por la arquitectura JavaTM para la implantación de la referencia de enlace (JAXB) XML v2.2.5 
    // Visite <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
    // Todas las modificaciones realizadas en este archivo se perderán si se vuelve a compilar el esquema de origen. 
    // Generado el: PM.08.06 a las 08:03:40 PM CEST 
    //
    
    package com.hopcroft.example.car;
    
    import javax.xml.bind.annotation.XmlRegistry;
    
    /**
     * This object contains factory methods for each 
     * Java content interface and Java element interface 
     * generated in the com.hopcroft.example.car package. 
     * <p>An ObjectFactory allows you to programatically 
     * construct new instances of the Java representation 
     * for XML content. The Java representation of XML 
     * content can consist of schema derived interfaces 
     * and classes representing the binding of schema 
     * type definitions, element declarations and model 
     * groups.  Factory methods for each of these are 
     * provided in this class.
     * 
     */
    @XmlRegistry
    public class ObjectFactory {
    
        /**
         * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.hopcroft.example.car
         * 
         */
        public ObjectFactory() {
        }
    
        /**
         * Create an instance of {@link Car }
         * 
         */
        public Car createCar() {
            return new Car();
        }
    
    }

The next step is creating our service that will accept any request to our resource (in this case our resource is a car). REST services are based in HTTP methods, so  we may implement different method that handler GET, POST, PUT or DELETE request (among others). It’s not the goal of this post to implement every HTTP method, so we are going to keep this class simple . We are going to implement the GET method to our car resource. Take a look at the CarResource class first:

package com.hopcroft.example.service;

import javax.ws.rs.GET;
import javax.ws.rs.Path;

import com.hopcroft.example.car.Car;
// car service
@Path("car")
public class CarResource {
	@GET
	public Car getCar() {
		Car car = new Car();
		car.setBrand("Ferrari");
		car.setModel("F40");
		car.setPrize(1000000);
		car.setYear(1995);
		return car;
	}
}

Creating a REST Service in Apache CXF is quite simple. Only thing you need to do is annotated your class with the @Path where your method will reply to request. In this case the path matches with the resources’ name. To define a method that replies to a HTTP GET request, we will need to annotate one method with the @GET annotation. The method will return a instance of one of our car. We might want to send the car’s id  in the request.

The only thing we need to do now is publishing our REST service to allow other people to call it. The way a REST service is published depends of the technology we use to develop it. In this case we need to use a special class from Apache CXF called JAXRSServerFactoryBean. Then we need to indicate the url where our service will reply.
Don’t forget that if you want to call the car service you need to append the string car at the end. Besides that you need to set the type of resources your REST service will handle (the car class in our case).

package com.hopcroft.example.server;

import org.apache.cxf.jaxrs.JAXRSServerFactoryBean;

import com.hopcroft.example.service.CarResource;

public class CarServer {
	public static void main(String[] args) {
		JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
		sf.setResourceClasses(CarResource.class);
		sf.setAddress("http://localhost:8080/");
		sf.create();
	}

}

Now, you need to run your server as a java application. To test your REST service you can create a java client, but it can be easier than that. Just open your web browser and type the url where your REST services is running. You may see something similar to that.

Car XML representation Apache CXF

You also can open the developer tools of your favorite browser to watch the request that has been sent.

 

RESTful services with Spring REST

Developing a REST service with Spring is as easy as with Apache CXF. Spring REST services are written on top of Spring MVC, i.e, you need towrite a controller in a specified path where your requests will be handle. First, we define a Car POJO with the same attributes that we also defined in the previous project. This car object will be sent as a response when a GET request comes. Let’s take a look at our Car controller.

package com.hopcroft.example.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import com.hopcroft.example.domain.Car;

@Controller
@RequestMapping("/car")
public class CarController {

   @RequestMapping(value="/car", method=RequestMethod.GET )
   public String getCar(ModelMap model) {
	   System.out.println("entro en el getCar");
       Car car = new Car();
       car.setBrand("Ferrari");
       car.setModel("F40");
       car.setPrize(1000000);
       car.setYear(1995);
       model.addAttribute("model", car);
       return "car";
   }
}

As you may notice we need to define where the resquest is mapped so that we define the url ‘/car’. To indicate that the method has to reply to a GET request we add the attribute ‘method=RequestMethod.GET’ to the @RequestMapping.

Why do we return the String “car” instead of the car object itself?. Well, we could have returned a ResponseBody object instead of a String and return a Car object then. But, if you know some insights about REST fundamentals, there are resources and
representations of those resources (REST means REpresentational state transfer). The state is refered to the resource itself (in this case a car), the representation defines how you represent that state (XML, JSON, HTML, a text document, …).
We need to inspect our config file to know how we define the different representations. This configuration are in the spring-mvc-servlet.xml:

<beans default-lazy-init="true"
	xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:util="http://www.springframework.org/schema/util" xmlns:security="http://www.springframework.org/schema/security"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:mvc="http://www.springframework.org/schema/mvc"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
	xsi:schemaLocation="
			http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
			http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
			http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd
			http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.xsd
			http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
			http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
			http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.0.xsd
			http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
            http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa.xsd">

	<mvc:annotation-driven />

	<context:component-scan base-package="com.hopcroft.example.controller" />

	<beans
		class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
		<property name="order" value="1" />
		<property name="mediaTypes">
			<map>
				<entry key="html" value="text/html" />
				<entry key="json" value="application/json" />
				<entry key="xml" value="application/xml" />
			</map>
		</property>
		<property name="viewResolvers">
			<list>
				<bean
					class="org.springframework.web.servlet.view.InternalResourceViewResolver">
					<property name="prefix" value="/WEB-INF/views/" />
					<property name="suffix" value=".jsp" />
				</bean>
			</list>
		</property>
		<property name="defaultViews">
			<list>
				<!-- Json View -->
				<bean
					class="org.springframework.web.servlet.view.json.MappingJacksonJsonView" />

				<!-- JAXB XML View -->
				<bean class="org.springframework.web.servlet.view.xml.MarshallingView">
					<constructor-arg>
						<bean class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
							<property name="classesToBeBound">
								<list>
									<value>com.hopcroft.example.domain.Car</value>
								</list>
							</property>
						</bean>
					</constructor-arg>
				</bean>
			</list>
		</property>
		<property name="ignoreAcceptHeader" value="true" />
	</bean>

	<bean
		class="">
		<property name="order" value="2" />
		<property name="prefix">
			<value>/WEB-INF/jsp/</value>
		</property>
		<property name="suffix">
			<value>.jsp</value>
		</property>
	</bean>

</beans>

First, we add the annotation-driven and component-scan element as you do in a typical Spring MVC project. After that we need to include a bean from the ContentNegotiatingViewResolver class. We need to configure this class in order to define the different representations that our service might use. In this bean we define 3 important properties:

  • mediaTypes. Our REST service replies in three different possible formats (XML, JSON and HTML).
  • defaultViews. Here we state which classes our JSON and XML views will use to return our Car object.

Finally we define a bean from the InternalResourceViewResolver class that will be used to write our Car within a JSP page.

To test the project we can run a jetty-server using Maven. So we type mvn jetty:run after compile it, open a browser. We have define different representations for the Car resource. So if we type http://localhost:8080/spring-mvc/car.xml we get a XML representation of a car.

Car XML representation

If we type http://localhost:8080/spring-mvc/car.json we get a JSON representation of a car. We can also inspect the developers tools to see how the request headers vary depending of which represention we ask for.

Car Json representation

If you wish to download this two project, you can find them in my GitHub account.

 

Some links you may find interested.

 

  • Pingback: REST Web Services with Apache CXF and Spring « hop2croft's software development Blog

  • Bpirvali

    Hi

    Thank you so much for the post.
    It is very helpful.
    When trying to run the Generator.java it does not create CarResource.java and CarServer.java?

    I would appreciate your help!
    Thanks,
    Behzad

    • hopcroft

      Helo Bpirvali,

      sorry for answering a week after you posted. I was fortunately on holidays :) .

      Both classes are created by me (you) in this case. They aren’t auto-generated.
      CarResource defines your resource, i.e, what you wanna get from your request. So that you have to define those HTTP method you want to expose (GET, POST, PUT, …)
      CarServer is only used to publish your resource so that you can fetch your resource through the HTTP methods you previously defined.

      Regards,
      hopcroft