Skip to main content
Create JAX WS Server

Create JAX WS Server

This chapter publishes the JAX-WS calculator interface from the previous topic. The server uses the interface as the service class and the implementation as the service bean, so the generated WSDL follows the annotations on the interface.

Server launcher

package com.example.ws;

import org.apache.cxf.feature.LoggingFeature;
import org.apache.cxf.jaxws.JaxWsServerFactoryBean;

public class CalculatorServer {

    public static void main(String[] args) {
        JaxWsServerFactoryBean factory = new JaxWsServerFactoryBean();
        factory.setServiceClass(Calculator.class);
        factory.setServiceBean(new CalculatorImpl());
        factory.setAddress("http://localhost:8080/calculator");
        factory.getFeatures().add(new LoggingFeature());

        factory.create();
        System.out.println("WSDL: http://localhost:8080/calculator?wsdl");
    }
}

Compile and start it:

mvn -q compile exec:java -Dexec.mainClass=com.example.ws.CalculatorServer

Check the contract

Open the WSDL URL and confirm three things: the target namespace matches the interface, the operation is named add, and the request elements are named a and b. Those names come directly from the annotations, not from the Java parameter names.

<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>

Test without a client

curl -s -X POST http://localhost:8080/calculator \
  -H "Content-Type: text/xml; charset=utf-8" \
  -H "SOAPAction: \"\"" \
  --data-binary @add-request.xml
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
  <soap:Body>
    <add xmlns="http://ws.example.com/">
      <a>7</a>
      <b>5</b>
    </add>
  </soap:Body>
</soap:Envelope>

The response should contain a return element with the value 12.

Deploy to a servlet container

For a traditional WAR, register CXF's servlet and publish the endpoint through Spring or the CXF servlet. A minimal web.xml mapping looks like this:

<servlet>
  <servlet-name>cxf</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
  <load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
  <servlet-name>cxf</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>

Endpoint addresses are relative to the servlet mapping, so an endpoint at /calculator is reachable at /services/calculator. Include the CXF Spring context files and a jaxws:endpoint declaration when you use Spring XML.

<jaxws:endpoint id="calculator"
    implementor="#calculatorImpl"
    address="/calculator"
    wsdlLocation="classpath:wsdl/calculator.wsdl"/>

<bean id="calculatorImpl" class="com.example.ws.CalculatorImpl"/>

Spring Boot alternative

The cxf-spring-boot-starter-jaxws dependency auto-configures the servlet and scans endpoints. Annotate the implementation with @WebService and register it as a bean; Spring Boot publishes it at the configured path. This is the least code for a new application, but the standalone launcher above is easier to understand while learning.

Production notes

  • Use an explicit target namespace and keep it stable across releases.
  • Log SOAP faults with enough context to reproduce the request.
  • Disable full payload logging when messages contain personal or payment data.
  • Set timeouts and thread pool limits for the servlet container or embedded Jetty.