Build contract first web services using CXF+JAXWS+JAXB & Spring
Today at work, I had to port a spring web services based application into using CXF. I found that the documentation of apache CXF is scattered all over the place and so I decided to write this one place stop to get one running . We will develop a 'complex' webservice that takes in the first name and last name of a person and returns it in the format lastname, firstname
Assumptions
1) You are familiar with the basics of Maven.
2) The steps outlined will have a affinity to use Eclipse as the IDE.
3) You will need JDK 1.5 or higher coz we will be using annotations.
The first step in developing the web service is to get your build system up.
Task 1: Setup the project in Eclipse.
Issue the command
mvn archetype:create -DgroupId=com.cxftest -DartifactId=CXFTest
This creates the basic skeleton of the project. Next, cd in to the cxftest directory and issue the following commands
mkdir src/main/webapp
mkdir src/main/resources
Next run
mvn eclipse:clean eclipse:eclipse -Dwtpversion=1.5
This creates the basic structure of your eclipse project.
Now lets add the dependencies needed by the project
<properties>
<cxf.version>2.1</cxf.version>
<spring.version>2.5</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-common-utilities</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
Task 2 :Define the contract
Define the schema / contract for communication.
a) Define the xsd schema for communication; lets call it NameFormat.xsd. This file will define both the input that the system expects as well as the expected output from the system. In other words this XML document defines the contract of the system.
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.cxftest.org" elementFormDefault="qualified">
<!-- Define the request -->
<xs:complexType name="FormatRequest">
<xs:sequence>
<xs:element name="firstName" type="xs:string" />
<xs:element name="lastName" type="xs:string" />
</xs:sequence>
</xs:complexType>
<!-- Define the response -->
<xs:complexType name="FormatResponse">
<xs:sequence>
<xs:element name="formattedName" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:schema>
Save this file under src/main/resources
Task 3: Automate all the mundane stuff.
Maven pitches in here to save a lot of time here so that we need to only concentrate on building our business logic.
First we need to setup JAXB, to execute the xjc task so that it generates Java classes from the XSD that we defined earlier.
for that add the following code to your POM.xml under the plugins section
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<packageName>com.cxftest.model</packageName> <!-- The name of your source package under which the source classes get generated -->
<schemaDirectory>src/main/resources</schemaDirectory> <!-- The path where you have placed the XSD -->
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
These two plugins will read the XSD and generate the source code of the expected inputs and output objects.
This is how the final POM will look
<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>com.cxftest</groupId>
<artifactId>CXFTest</artifactId>
<packaging>war</packaging>
<version>1.0-SNAPSHOT</version>
<name>CXFTest</name>
<url>http://maven.apache.org</url>
<properties>
<cxf.version>2.1</cxf.version>
<spring.version>2.5</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-core</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-common-utilities</artifactId>
<version>${cxf.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxb2-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>xjc</goal>
</goals>
</execution>
</executions>
<configuration>
<!--
The name of your source package under which the source classes get
generated
-->
<packageName>com.cxftest.model</packageName>
<!--
The path where you have placed the XSD from which the code needs
to generated
-->
<schemaDirectory>src/main/resources</schemaDirectory>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
Task 4: Code the web service.
Now code the implementation of the web services. Following the grand tradition of coding to interfaces lets define the interface for the web service as shown below.
package com.cxftest.service;
import javax.jws.WebMethod;
import javax.jws.WebService;
import com.cxftest.model.FormatRequest;
import com.cxftest.model.FormatResponse;
@WebService(targetNamespace="http://www.cxftest.org")
public interface NameFormatterService {
@WebMethod
public abstract FormatResponse formatName(FormatRequest request);
}
After this is done, lets Code the implementation of what our web service is supposed to do.
/**
*
*/
package com.cxftest.service;
import javax.jws.WebMethod;
import javax.jws.WebService;
import com.cxftest.model.FormatRequest;
import com.cxftest.model.FormatResponse;
/**
* @author jvictor
*
*/
@WebService (targetNamespace="http://www.cxftest.org", endpointInterface="com.cxftest.service.NameFormatterService")
public class NameFormatterServiceImpl implements NameFormatterService {
/* (non-Javadoc)
* @see com.cxftest.service.NameFormatterService#formatName(com.cxftest.model.FormatRequest)
*/
@WebMethod
public FormatResponse formatName(FormatRequest request){
FormatResponse response = new FormatResponse();
response.setFormattedName(request.getLastName() "," request.getFirstName());
return response;
}
}
Task 5: Wire up everything
The first thing that we need to do is to declare a servlet in our web.xml and configure it to receive all incoming requests. My web .xml looks like this
<?xml version="1.0" encoding="UTF-8"?>
<web-app id="WebApp_9" version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:appContext.xml</param-value>
</context-param>
<listener>
<listener-class> org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>
org.apache.cxf.transport.servlet.CXFServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>
Note the <context-param> and <listener> are being defined in the web.xml, this is how we bootstrap spring.
Also note how an instance of org.apache.cxf.transport.servlet.CXFServlet is used to service all requests.
The final part in the JIGSAW is the spring application context xml definition for spring.
<?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:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:jaxws="http://cxf.apache.org/jaxws"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd"
default-dependency-check="none" default-lazy-init="false">
<!-- Load the needed resources that are present in the cxf* jars -->
<import resource="classpath:META-INF/cxf/cxf.xml" />
<import resource="classpath:META-INF/cxf/cxf-extension-soap.xml" />
<import resource="classpath:META-INF/cxf/cxf-servlet.xml" />
<!-- Hook up the web service -->
<jaxws:endpoint
id="formatterService"
implementor="com.cxftest.service.NameFormatterServiceImpl"
address="/format" />
</beans>
Task 6:
Finally run
mvn eclipse:clean eclipse:eclipse -Dwtpversion=1.5
mvn clean compile
Refresh the project and fire up the webservice !

11 Comments:
Hi Victor,
Thanks for writing this blog. this looks neat and understandable but still it looks like some holes.
I haven't understand from Task 5.
my questions are:
1. After creating web.xml file what is next? you given some xml code but what is that file name of xml?
2. where to keep that xml file? i mean in which folder
3. After excute final command then how to run example?
4. where is client code to access services?
5. After we did all from command prompt then do we need to import it into eclipse or not? if yes then as what type(java, maven or web) of projects?
In task 1 mkdir path is not working. change as mkdir \src\main\webapp then it's working.
please give me some clues on above quires.
Many Thanks
sduser
1. After creating web.xml file what is next? you given some xml code but what is that file name of xml?
The file in Step 5 is the applicationContext.xml It is the spring config file. It can be placed anywhere in the classpath.
2. where to keep that xml file? i mean in which folder
I would place it under src/main/resources
3. After excute final command then how to run example?
You need a eclipse+wtp setup with a server such as tomcat. Rt Click Run as > Run on server
4. where is client code to access services?
You can use a tool called soapUI. First you need to run the application and get the wsdl url from the running application.
After we did all from command prompt then do we need to import it into eclipse or not? if yes then as what type(java, maven or web) of projects?
This tutorial assumes that you are using Eclipse + WTP bundle as the IDE. you execute all the commands from the workspace of your eclipse setup.
Its a WTP web project, You just need to import the project if your project is not in the workspace. The Eclipse+WTP setup will take care of converting the project into a web project based on the config files generated by maven.
In task 1 mkdir path is not working. change as mkdir \src\main\webapp then it's working.
Are you using windows ? if so / will not work. (I gave up on windows after they released vista.)
Hi Victor,
Thanks for this - very helpful for getting up and running with CXF. But isn't it still a code-first approach? It doesn't look like the NameFormat.xsd file is actually used in the code or enforced in any way. I tried changing the type names in NameFormat.xsd and the example still worked.
Well its an open ended question, Upfront CXF is not as contract first-ish when compared to stuff like Spring-WS.
My perspective is that the data contract is defined in the nameformat.xsd file. The java classes needed to define the contract are generated at runtime. So you typically focus on what the WS has to do rather than writing boiler plate code to define the model and all the other nuances.
As far as I know, spring-ws uses the same approach for contract-first (only one supported) by defining the contract as an .xsd schema, then generating the wsdl from that
Thanks for the tip, good work..
hi victor,
i recently started with web services.i first started with web service classes and generated the wsdl using java2wsdl. then i generated client using wsdl2java.but was unable to execute the client. i am using springs and cxf.it works fine with JaxWsProxyFactoryBean.but wanted to generate a client using wsdl.
http://www.swastikwebby.com
hello, our company provide highly experienced and talented web designer,our capacity to build a powerful and attractive Finance comparison website.Specially For Traveling website / Real Estate / Matrimonial / Visa / eShopping / Education / School / College / Custom Websites.
contact us: +91 972 570 7728
Hi, I have a WSDL for my webservice. You use an xsd. Is there any way to generate code from WSDL instead?
I tried the soapui nature, which has has a generate code method, but it always crashes eclipse when you fire it up.
This comment has been removed by the author.
thanks victor your blog is very helpful
Post a Comment
Subscribe to Post Comments [Atom]
Links to this post:
Create a Link
<< Home