Developing a simple SOAP-webservice using Spring 3.0.1 and Apache CXF 2.2.6

In the past few years many techniques have been developed to help applications interact with each other. One of them are webservice-interfaces. These interfaces are extremly popular in the world of Java software development. One Framework that can be used to build such interfaces is Apache CXF. Apache CXF delivers a toolset to develop interfaces using different protocols like XML/HTTP, RESTful HTTP, Corba and SOAP. In this article i'd like to show how easy it could be to develop a simple SOAP-webservice based on Apache CXF 2.2.6 and the Spring Framework 3.0.1. You can download the full example at the bottom of this article.
Setting up the project...
First I set up a small Maven 2 project that packages my application as a web application archive (*.war-file). Therefore I created the following pom.xml:
- <project xmlns="...">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.unitedcoders.demo</groupId>
- <artifactId>CXFExampleService</artifactId>
- <packaging>war</packaging>
- <version>0.0.1-SNAPSHOT</version>
- <name>Example Apache CXF Webservice</name>
- <url>http://united-coders.com</url>
- <!-- Dependency properties -->
- <properties>
- <junit-version>4.5</junit-version>
- <cxf.version>2.2.6</cxf.version>
- <spring-version>3.0.1.RELEASE</spring-version>
- <commons-logging-version>1.1.1</commons-logging-version>
- </properties>
- <!-- Plugin configuration -->
- <build>
- <finalName>CXFExampleService</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>
- <plugin>
- <groupId>org.apache.cxf</groupId>
- <artifactId>cxf-java2ws-plugin</artifactId>
- <version>${cxf.version}</version>
- <dependencies>
- <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-frontend-simple</artifactId>
- <version>${cxf.version}</version>
- </dependency>
- </dependencies>
- <executions>
- <execution>
- <id>process-classes</id>
- <phase>process-classes</phase>
- <configuration>
- <className>com.unitedcoders.demo.PersonService</className>
- <genWsdl>true</genWsdl>
- <verbose>true</verbose>
- </configuration>
- <goals>
- <goal>java2ws</goal>
- </goals>
- </execution>
- </executions>
- </plugin>
- </plugins>
- </build>
- <!-- Dependency definitions -->
- <dependencies>
- <!-- Apache CXF dependencies -->
- <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>
- <!-- Spring Dependencies -->
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-core</artifactId>
- <version>${spring-version}</version>
- </dependency>
- <dependency>
- <groupId>org.springframework</groupId>
- <artifactId>spring-web</artifactId>
- <version>${spring-version}</version>
- </dependency>
- <!-- Logging -->
- <dependency>
- <groupId>commons-logging</groupId>
- <artifactId>commons-logging</artifactId>
- <version>${commons-logging-version}</version>
- </dependency>
- <!-- Testing -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- <version>${junit-version}</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
- </project>
My projects structure
- phil@invader:~/Projects/CXFExample$ tree
- .
- |-- README.txt
- |-- pom.xml
- `-- src
- |-- main
- | |-- java
- | | `-- com
- | | `-- unitedcoders
- | | `-- demo
- | | |-- Person.java
- | | |-- PersonService.java
- | | `-- PersonServiceImpl.java
- | |-- resources
- | | `-- application-context.xml
- | `-- webapp
- | `-- WEB-INF
- | `-- web.xml
- `-- test
- `-- java
- `-- com
- `-- unitedcoders
- `-- demo
- |-- PersonServiceImplTest.java
- `-- PersonTest.java
- 14 directories, 9 files
- phil@invader:~/Projects/CXFExample$
Let's first take a look on what has happened here. I defined some Apache CXF 2.2.6 dependencies which are needed to create my SOAP-webservice. To use the Spring framework in my little project I also added spring-core and spring-web in version 3.0.1 to my dependencies. Additionally I defined some other dependencies like JUnit and Apache commons-logging. But what has happend to the Maven 2 plugins? The first plugin I configured in my project is the maven-compiler-plugin. This plugin is a plugin of Mavens standard lifecycle. My configuration lets Maven 2 know which Java version should be used to compile my source. I prefer to use Java 1.6. The second plugin I defined is the cxf-java2ws-plugin. This Maven 2 plugin helps me to generate a WSDL-file from my annotated Java webservice-class.
Developing the SOAP webservice
To have a little showcase I created a simple class "Person" containing the only one member field "name". Later on the webservice should get a persons name from a client and answer with a short greeting like „Hello [NAME]!“.
- package com.unitedcoders.demo;
- public class Person {
- private String name;
- public Person(String name) {
- this.name = name;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
- package com.unitedcoders.demo;
- import javax.jws.WebService;
- @WebService
- public interface PersonService {
- public String greetPerson(String name);
- }
- package com.unitedcoders.demo;
- import javax.jws.WebService;
- @WebService(endpointInterface = "com.unitedcoders.demo.PersonService")
- public class PersonServiceImpl implements PersonService {
- public String greetPerson(String name) {
- Person person = new Person(name);
- return "Hello " + person.getName() + "!";
- }
- }
Combining everything
To get the webservice working I finally combined Spring and my webservice-implementation. Therefore I first defined the applications context. First I added three imports to my applications context. There are three imports that add CXF-specific bean definitions and configurations to my applications context. After that a singleton bean of my webservice is needed. And at least a jaxws:endpoint is defined that maps my bean to the endpoint to the path "/personService".
application-context.xml:
- <?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:jaxws="..."
- xsi:schemaLocation="...">
- <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" />
- <!-- Spring manage ServiceBean -->
- <bean id="personServ" class="com.unitedcoders.demo.PersonServiceImpl" />
- <!-- JAX-WS Service Endpoint -->
- <jaxws:endpoint id="personService" implementor="#personServ" address="/personService" />
- </beans>
- <?xml version="1.0" encoding="UTF-8"?>
- <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="...">
- <display-name>CXF Example Webservice</display-name>
- <listener>
- <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
- </listener>
- <context-param>
- <param-name>contextConfigLocation</param-name>
- <param-value>classpath:application-context.xml</param-value>
- </context-param>
- <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>
Testing the new SOAP-webservice
After building this Maven 2 project with „mvn clean package“ a new war-file will be placed in the target folder. This war-file now contains an entire webservice. If it is deployed on a Java web container like Apache Tomcat you can reach the webservice by accessing it in your browser.
http://[YOUR TOMCAT]:[PORT]/CXFExampleService/personService?wsdl

To run some functional tests on the new webservice an test if the webservice works as expected I used soapUI which can be downloaded here. soapUI is a really famous tool that can be used to test webservices. It can be used as a standalone application or as a IDE plugin (e.g. for eclipse).

Download the full example:
Some resources:
http://cxf.apache.org
http://www.springsource.org/download
http://www.soapui.org
Trackback URL for this post:
| Attachment | Size |
|---|---|
| united-coders.com-CXFExample.tar_.bz2 | 2.53 KB |

Comments
Anonymous (not verified) - Mon, 03/01/2010 - 10:48
Thanks for your guide!
Anonymous (not verified) - Thu, 03/04/2010 - 00:40
good work, I appreciate it! detailed clean and easy to understand!
Andrew (not verified) - Tue, 03/09/2010 - 16:35
Can you give us a little more insight into the cxf files referenced within the application-context.xml?
I don't see those files in your tar file. What a they for and are they needed?
Phillip Steffensen - Wed, 07/14/2010 - 20:45
The cxf files referenced in application-context.xml are delivered by the cxf dependencies.
You can take a closer look on them if you browse into these dependencies.
Christian Harms - Wed, 04/28/2010 - 07:34
Found a deployment-question on stackoverflow: http://stackoverflow.com/questions/2635660/apache-cxf-cxf-java2ws-plugin...
Anonymous (not verified) - Wed, 05/05/2010 - 18:06
Excellent work, just what I was looking for!-)
Anonymous (not verified) - Wed, 06/23/2010 - 15:02
hi,
Thanks you for your example. But i 'd like to ask you in which directory is generated the wsdl using the plugin cxf-java2ws-plugin.
Vincent (not verified) - Tue, 07/20/2010 - 08:39
Hi,
Excellent Job you did, it is very very useful to me.
Thanks,
Vincent
Rajesh Kollam (not verified) - Wed, 07/28/2010 - 08:11
Ecellent example. This is really helped me.
Vlad (not verified) - Tue, 08/31/2010 - 00:25
Excellent example, would be nice if wsdl had Person::name like in java rather than Person::arg0.
Also it offers manual testing using SOAP UI rather than having honest http junit test.
Vlad (not verified) - Tue, 08/31/2010 - 00:55
Here is the fix to make wsdl look better (person should have "name" attribute instead of "arg0"):
public String greetPerson(@WebParam(name = "name") String name);