Apache CXF is an open-source Web Services framework supporting both JAX-WS and JAX-RS. This means that we could create a service and offer it both as RESTful Web Service and traditional SOAP based Web Service. With CXF when you get the WSDL file (we will see how) or WADL (REST equivalent of WSDL) you can pass the link to the ones who are to write a client application and they can use it to configure the plugin and the required code is generated. With Maven things become even simpler.
Let’s go into a demo application. The application is to search for employees in a particular unit(group) with a unit id and the date (between joining date – date of resignation/active employee). I first create an Employee class with some basic attributes.
@XmlRootElement
public class Employee implements Serializable { … }
Important to mark it as @XmlRootElement so it appears in the schema and for marshalling/unmarshalling object.
Now let’s create the service interface, the first one we create is a SOAP service interface:
/* Mark as a Web Service – Similarly method further down */
@WebService
public interface IEmployeeSearch {@WebMethod
public EmployeeList getEmployees(@WebParam(name=”unitID”, targetNamespace=”http://service.kentor.lab.se/”) UnitID unitID,
@WebParam(name=”interval”) Interval interval);
}
It does not take String; int parameters but something complex which you would use as in a real application. UnitID is a simple setter and getter class on String object. Two reasons for using this way is:
- It is very self descriptive what one needs to send.
- You have the flexibility to mark it to any schema type you like @XmlSchemaType(name = “string”). That you could do it only in a wrapper class, a shortcoming in Apache CXF.
Remember @XmlRootElement annotation in the above classes. Now the RESTful interface:
@GET
@Consumes(MediaType.APPLICATION_XML)
@Produces(MediaType.APPLICATION_XML)
@ElementClass(response=EmployeeList.class)
public EmployeeList getEmployees(@Description(“find employees with UnitID”) UnitID unitID,
@Description(“interval date (joningDate-resignationDate)”) Interval interval);
It is important that the two interfaces are just the same but only differ with annotations. Now the actual implementation (free of annotation):
public class EmployeeSearch implements IEmployeeSearch, IRestEmployeeSearch {
public EmployeeList getEmployees(UnitID hsaID, Interval datum) { … }
}
You might be wondering why not return Listinstead of EmployeeList. A bug in Apache CXF which cannot handle List/Map types and we must write a wrapper in order for it to produce a complete WADL file. Without wrapper class it generates a WADL without describing what the return attributes will be which are more clear in WSDL.
Most important part the Maven configuration:
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>2.5.2</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
<version>2.5.2</version>
</dependency>
Now you need to configure your.xml with SOAP and REST URLs
<!– SOAP configuration –>
<jaxws:endpoint implementor=”se.kentor.lab.service.EmployeeSearch”
address=”/findEmployees” /><!– REST WebServices configuration –>
<jaxrs:server address=”/rest/findEmployees”>
<jaxrs:serviceBeans>
bean=”empSearch” />
<!–jaxrs:serviceBeans>
<!–jaxrs:server>
<bean id=”empSearch” class=”se.kentor.lab.service.EmployeeSearch” />
You have to configure your web.xml to use CXFServlet class with your desired mapping URL. CXF uses Spring Framework. The contextConfigLocation should be defined which would point to the.xml. Now deploy your application and when you access the page http://xxx:xx/app-name/url-pattern/ then you should see something like this:
Give this URL of WSDL or WADL to one who is developing the client and they could generate the required classes and code smoothly if they use Apache CXF plugin (or maybe with other tools also). Configure in pom.xml for the plugins:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>2.5.2</version>
<configuration>
src/main/java/
<wsdlOptions>
<wsdlOption>
<!– <wsdl>${basedir}/src/main/resources/il.wsdl
<wsdl>http://localhost:8080/CXFDualWebService/services/findEmployees?wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
</plugin>
OR WADL
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-wadl2java-plugin</artifactId>
<version>2.5.2</version>
<configuration>
src/main/src/
<wadlOptions>
<wadlOption>
<!– ${basedir}/src/main/resources/il.wsdl–>
<wadl>http://localhost:8080/CXFDualWebService/services /rest/findEmployees?_wadl</wadl>
</wadlOption>
</wadlOptions>
</configuration>
</plugin>
It is quite straight forward to figure-out how to use this generated classes and you can configure further more when you read about these plugins.
Some tips:
- If you want xsd:date instead of xsd:datetime in your WSDL or WADL then mark on the getter method @XmlSchemaType(name = “date”) so it recognizes it properly (example in Employee class in this case)
- Use @Consumes when you have parameters other than String, int,… and mark that class as @XmlRootElement
- If you are looking for more posts on the topic of Web Services then look at the other posts on this blog. I had also written a post on Web Service client application using Apache CXF.
