Apache CXF with WSDL First
Contract-first development treats the WSDL as the source of truth. The contract is reviewed and versioned before implementation starts, and Java classes are generated from it. This keeps SOAP clients in other languages aligned with the service.
Anatomy of a WSDL
- definitions - the root element and namespace declarations.
- types - XML schemas for request and response payloads.
- message - named parts that reference schema elements.
- portType - the abstract interface: operations, inputs, and outputs.
- binding - how operations map to SOAP over a transport.
- service - one or more ports with concrete addresses.
<definitions xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:tns="http://ws.example.com/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://ws.example.com/"
name="CalculatorService">
<types>
<xsd:schema targetNamespace="http://ws.example.com/">
<xsd:element name="add">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="a" type="xsd:int"/>
<xsd:element name="b" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="addResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="return" type="xsd:int"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</types>
<message name="addRequest">
<part name="parameters" element="tns:add"/>
</message>
<message name="addResponse">
<part name="parameters" element="tns:addResponse"/>
</message>
<portType name="Calculator">
<operation name="add">
<input message="tns:addRequest"/>
<output message="tns:addResponse"/>
</operation>
</portType>
<binding name="CalculatorPortBinding" type="tns:Calculator">
<soap:binding style="document"
transport="http://schemas.xmlsoap.org/soap/http"/>
<operation name="add">
<soap:operation soapAction=""/>
<input><soap:body use="literal"/></input>
<output><soap:body use="literal"/></output>
</operation>
</binding>
<service name="CalculatorService">
<port name="CalculatorPort" binding="tns:CalculatorPortBinding">
<soap:address location="http://localhost:8080/calculator"/>
</port>
</service>
</definitions>
Generate Java from the WSDL
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>${cxf.version}</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${project.basedir}/src/main/resources/wsdl/calculator.wsdl</wsdl>
<extraargs>
<extraarg>-p</extraarg>
<extraarg>com.example.calculator</extraarg>
</extraargs>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals><goal>wsdl2java</goal></goals>
</execution>
</executions>
</plugin>
mvn generate-sources
The generated code includes the service interface, a service class, and JAXB types for the schema elements. Add the generated directory to your IDE source path if it does not appear automatically.
Why start from the contract
- Clients in .NET, Python, or another Java stack can be generated before the service exists.
- Schema changes are reviewed as interface changes, not as accidental side effects of refactoring.
- WSDL and XSD can be published to a registry and versioned independently.
- Multiple implementations can satisfy the same contract during a migration.
Practical rules
Use a stable target namespace, avoid anonymous inline types where reuse matters, and keep operation names meaningful. Test the WSDL with a generic tool such as SoapUI before writing the implementation; most interoperability problems are visible at that stage.
Back to course overview · Previous: Create JAX-WS Client & Test · Next: Create WSDL Server