CXF provides the 'simple' frontend to map Java APIs to and from WSDL models for web services. The simple front end is much like JAX-WS, however, where JAX-WS uses Java annotations to specify detailed configuration (and, indeed, requires a few), Simple is willing to map a 'naked' interface or class to a service, and respects some configuration options from .aegis.xml files shared with the Aegis data binding.
Most Applications Should Use JAX-WS
The JAX-WS frontend is far more flexible than the Simple frontend. There are only two reasons to select Simple over JAX-WS:
- You must avoid the use of Java annotations. JAX-WS requires them, Simple does not.
- You want to have the absolutely smallest possible collection of additional dependencies. JAX-WS has more dependencies than Simple.
Other than these items, Simple has no advantages over JAX-WS. The implementation classes of JAX-WS in CXF are all subclasses of the implementation classes of Simple. In a 'simple' case, very nearly identical things happen in the Simple front end as in JAX-WS. CXF's extensions to JAX-WS, on the other hand, make it very 'simple' to use.
Simple Pitfall: Unreliable Parameter Names
The following pitfall exists, in fact, for both Simple and JAX-WS, but it is much easier to avoid it with JAX-WS.
The typical pattern of a web service is to define a Service Endpoint Interface and then create a class that implements that interface. When you own both ends of the process, you can simply use the SEI in both the server and the client.
The problem has to do with a quirk of Java reflection. If a program uses Java reflection to examine a concrete method of a class, the Java Language Specification requires the system to provide the parameter names from the source. However, if a program uses reflection to look at an abstract method, the specification does not require parameter names.
This leads to ugly parameters named arg0
, arg1
, ... Further, if you forget to specify the SEI when creating a service, and only provide the SEB, Simple will see your concrete methods and assign actual parameter names. If you client uses the SEI, they won't communicate.
Thus, while JAX-WS @WebParam
annotations may seem noisy and inconvenient, they are, in fact, ensuring that your service has a consistent contract.
If you choose to use the Simple front end, you will need to use parameter
elements in a .aegis.xml
file to specify the parameter names or be sure to provide the SEI to the ServerFactoryBean
.
Simple and Data Bindings
By default CXF uses the JAXB databinding. This is a historical default, but often not what you will want, both due to the pitfall described above and the JAX-B issue described at the bottom of this page. If you choose to use the Simple front end, we recommend that you use the Aegis databinding.
ServerFactoryBean – Making a Service Endpoint
The ServerFactoryBean produces a Server instance for you. It requires a service class and an address to publish the service on. By creating a Server you'll have started your service and made it available to the outside world.
First you'll want to create your service class:
public interface HelloWorld { String sayHi(String text); }
This does not have to be an interface, but we're going to use an interface for this example because
- It is good to separate out your service contract (your interface) from your implementation
- This allows us to easily create a Java Proxy client
We'll also need an implementation class:
public class HelloWorldImpl implements HelloWorld { public String sayHi(String text) { return "Hello " + text; } }
And now we'll want to create a Server from this
import org.apache.cxf.frontend.ServerFactoryBean; ... // Create our service implementation HelloWorldImpl helloWorldImpl = new HelloWorldImpl(); // Create our Server ServerFactoryBean svrFactory = new ServerFactoryBean(); svrFactory.setServiceClass(HelloWorld.class); svrFactory.setAddress("http://localhost:9000/Hello"); svrFactory.setServiceBean(helloWorldImpl); svrFactory.create();
Your service is now started! You can access the wsdl at "http://localhost:9000/Hello?wsdl".
ClientProxyFactoryBean – Making a Client Proxy
You'll also want to create a client for your service. CXF includes a ClientProxyFactoryBean which will create a Java proxy for you from your interface which will invoke the service.
import demo.hw.server.HelloWorld; import org.apache.cxf.frontend.ClientProxyFactoryBean; ... ClientProxyFactoryBean factory = new ClientProxyFactoryBean(); factory.setServiceClass(HelloWorld.class); factory.setAddress("http://localhost:9000/Hello"); HelloWorld client = (HelloWorld) factory.create();
You simply need to set your service class and your service's URL on the bean. Calling create() will then create a proxy for you based on your interface.
Configure with Spring
The XML configuration for do-it-yourself Spring beans and cxf.xml or cxf-servlet.xml are all very similiar.
The simple front-end does not have its own extension, so you don't need any extra imports if are setting up your
own application context.
Here's an example cxf-servlet.xml with simple front end endpoint configuration. If you use your own application context, you'll need to import the soap extension and http servlet extension.
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:simple="http://cxf.apache.org/simple" xmlns:soap="http://cxf.apache.org/bindings/soap" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd http://cxf.apache.org/bindings/soap http://cxf.apache.org/schemas/configuration/soap.xsd http://cxf.apache.org/simple http://cxf.apache.org/schemas/simple.xsd"> <simple:server id="pojoservice" serviceClass="demo.hw.server.HelloWorld" address="/hello_world"> <simple:serviceBean> <bean class="demo.hw.server.HelloWorldImpl" /> </simple:serviceBean> </simple:server> </beans>
Deploying Simple FrontEnd service to a container
If you are looking to deploy the service to a container follow the steps in "Transports->HTTP Transport -> Servlet Transport" section from the Table of contents. Add the xml content from the above section "Configure cxf-servlet.xml". Name your configuration file as say services.xml. Do not name it as cxf-servlet.xml.
You need to add the import statements from the sample configuration file in "Transports->HTTP Transport -> Servlet Transport"
Well-Known Issue
There is a known issue for the JAXB data binding with POJO, please see Dan Kulp's comment in https://issues.apache.org/jira/browse/CXF-897 .
If you want to use JAXB binding you should use the JAX-WS Frontend. Mixing Simple Frontend and JAXB binding leads to problems. The article A simple JAX-WS service shows a code first JAX-WS service that is almost as easy to use as the Simple Frontend.