Create Client & Test
A CXF client can be built dynamically from the WSDL or statically from an interface. The dynamic approach needs no generated code, which makes it useful for a quick test of a POJO endpoint.
Dynamic client
package com.example.pojo;
import org.apache.cxf.endpoint.Client;
import org.apache.cxf.jaxws.endpoint.dynamic.JaxWsDynamicClientFactory;
public class DynamicClient {
public static void main(String[] args) throws Exception {
JaxWsDynamicClientFactory factory = JaxWsDynamicClientFactory.newInstance();
Client client = factory.createClient("http://localhost:8080/greeting?wsdl");
Object[] reply = client.invoke("greet", "Ada");
System.out.println(reply[0]);
}
}
The operation name comes from the WSDL. Arguments are passed in declaration order and the result is returned as an object array. Run it with Maven while the server is still running:
mvn -q compile exec:java -Dexec.mainClass=com.example.pojo.DynamicClient
Expected output: Hello, Ada.
Interface-based client
For maintained code, define an interface that matches the service and let CXF create a proxy. This gives compile-time checking and avoids string-based operation names.
import jakarta.jws.WebService;
@WebService(targetNamespace = "http://pojo.example.com/")
public interface GreetingPort {
String greet(String name);
}
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(GreetingPort.class);
factory.setAddress("http://localhost:8080/greeting");
GreetingPort port = (GreetingPort) factory.create();
System.out.println(port.greet("Grace"));
The interface must use the same namespace and operation names as the WSDL. When the namespace is missing, CXF may create a proxy that sends a request the server does not recognize.
Test with JUnit
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class GreetingClientTest {
@Test
void callsTheRemoteGreeting() {
JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.setServiceClass(GreetingPort.class);
factory.setAddress("http://localhost:8080/greeting");
GreetingPort port = (GreetingPort) factory.create();
assertEquals("Hello, Lin", port.greet("Lin"));
}
}
Integration tests that depend on a running server are slower and less reliable than unit tests. Keep a small number of them for protocol checks, and stub the service interface for business-logic tests.
Troubleshooting
- Connection refused - the server is not running on the expected port.
- 404 on the WSDL - the address path differs from the server's path.
- Unmarshalling error - namespaces or element names do not match the contract.
- Slow first call - the dynamic client is downloading and compiling the WSDL; later calls are faster.
- Proxy cast failure - the interface is not compatible with the generated service.
Inspect the traffic
Add LoggingFeature to the proxy factory, or use SoapUI to see the exact XML. Comparing a working request with a failing one is faster than guessing which namespace is wrong.
Back to course overview · Previous: Create Server · Next: Apache CXF with JAX-WS