Developing Web Services on WildFly 41

TL;DR: This guide updates SOAP-based web service development for WildFly 41.0.1.Final and Jakarta EE 11. Learn how to implement endpoints using the jakarta.xml.ws namespace, configure the reference Apache CXF stack, manage timeouts, differentiate between JAX-WS handlers and CXF interceptors, and handle cloud deployments with reverse proxies.

webservicesIn this tutorial, we will show how to develop, deploy, and test a SOAP Web Service on WildFly 41.0.1.Final using Jakarta XML Web Services (formerly JAX-WS) and Jakarta EE 11. Although RESTful APIs are widely adopted, SOAP remains highly relevant for enterprise integrations that demand strict contract validation (WSDL), transactional support (WS-Coordination), and robust, message-level security standards (WS-Security).

WildFly 41 ships with Apache CXF (via the JBossWS-CXF integration) as its reference SOAP stack. This modern stack provides full support for the Jakarta EE 11 programming model, replacing legacy stacks like JBossWS Native and outdated specifications like JAX-RPC.

SOAP vs REST in Enterprise Architecture

While REST is often preferred for public-facing, lightweight web and mobile APIs due to its simplicity and JSON support, SOAP remains the standard for robust, contract-first B2B integration. SOAP relies on an explicit service contract (WSDL) and supports complex WS-* specifications such as WS-ReliableMessaging and WS-Security. Rather than looking at REST as a universal replacement, modern enterprise developers treat SOAP and REST as complementary tools, choosing SOAP where strict transactions, formal contracts, and complex message-level security are required.

Configuring the Webservices Subsystem in WildFly 41

To use Web Services in WildFly 41, the server configuration must include the webservices extension and its subsystem. In modern WildFly versions, this subsystem is enabled by default in standard configuration files (such as standalone.xml and standalone-full.xml). You can verify its presence using the WildFly CLI:

/subsystem=webservices:read-resource

If you need to configure or verify the subsystem manually, ensure the following extension and subsystem definitions are present in your configuration file:

<extension module="org.jboss.as.webservices"/>

<subsystem xmlns="urn:jboss:domain:webservices:2.0">
    <wsdl-host>jbossws.undefined</wsdl-host>
    <endpoint-config name="Standard-Endpoint-Config"/>
    <endpoint-config name="Recording-Endpoint-Config">
        <pre-handler-chain name="recording-handlers" local-only="true">
            <handler name="RecordingHandler" class="org.jboss.ws.common.invocation.RecordingServerHandler"/>
        </pre-handler-chain>
    </endpoint-config>
</subsystem>

Creating a JAX-WS Web Service using Jakarta EE 11

Let's create a simple Web Service packaged inside a Web application (WAR). First, we define the Service Endpoint Interface (SEI) using the jakarta.jws annotations:

package com.sample;

import jakarta.jws.WebMethod;
import jakarta.jws.WebService;

@WebService
public interface Math {
    @WebMethod
    public long sum(long a, long b);
}

Next, we write the corresponding Web Service Implementation Bean (SIB):

package com.sample;

import jakarta.jws.WebService;

@WebService(endpointInterface = "com.sample.Math", serviceName = "MathWS")
public class MathWS implements Math {
    
    @Override
    public long sum(long a, long b) {
        System.out.println("Summing " + a + " + " + b);
        return a + b;
    }
}

Deployment Configuration

Under Jakarta EE 11, Web Services can be deployed implicitly without any web.xml servlet mappings; the container automatically detects classes annotated with @WebService and exposes them. However, if you need to customize URL mappings or security constraints, you can declare them in a Jakarta EE 11 compliant web.xml (using Schema Version 6.0):

<web-app xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
         version="6.0">
    <servlet>
        <servlet-name>MathWS</servlet-name>
        <servlet-class>com.sample.MathWS</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>MathWS</servlet-name>
        <url-pattern>/MathWS</url-pattern>
    </servlet-mapping>
</web-app>

Once compiled, pack the application into a Web Archive (e.g., balance.war) and deploy it to WildFly. You can deploy using Maven, the wildfly-maven-plugin, or by copying the archive directly to the standalone/deployments/ directory.

Verifying and Managing Endpoints

In legacy JBoss AS 7, endpoint monitoring was often handled by custom, outdated console pages. In WildFly 41, you can manage and inspect active web service endpoints directly through the modern administration console, typically located at http://localhost:9990/console.

Navigate to Runtime > Subsystems > Webservices to view active services, their deployments, and access their generated WSDL URLs (e.g., http://localhost:8080/balance/MathWS?wsdl).

JBoss 7 Web service tutorial
Note: The administrative interface has been updated in WildFly 41, but the foundational ability to query deployed services and trace their endpoints remains central to JBossWS administration.

Writing a Modern Apache CXF Client

To call the web service, you can write a Java client utilizing modern Apache CXF APIs. In CXF 4.x (used by WildFly 41), the legacy logging interceptors have been replaced by the modern high-performance logging framework. Make sure to include the cxf-rt-features-logging dependency in your client environment.

package com.sample;

import org.apache.cxf.ext.logging.LoggingInInterceptor;
import org.apache.cxf.ext.logging.LoggingOutInterceptor;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;

public class Client {

    public static void main(String args[]) throws Exception {

        JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();

        // Modern CXF logging interceptors
        factory.getInInterceptors().add(new LoggingInInterceptor());
        factory.getOutInterceptors().add(new LoggingOutInterceptor());
        
        factory.setServiceClass(Math.class);
        factory.setAddress("http://localhost:8080/balance/MathWS");
        
        Math client = (Math) factory.create();
        System.out.println("Server said: " + client.sum(3, 4));
    }
}

JAX-WS Handlers vs. Apache CXF Interceptors

When extending the functionality of your SOAP services (e.g., logging, header manipulation, or auditing), you must choose between standard JAX-WS Handlers and CXF Interceptors:

  • JAX-WS Handlers (Portable): Standard components defined by the Jakarta XML Web Services specification (such as jakarta.xml.ws.handler.soap.SOAPHandler). They are highly portable across different Jakarta EE application servers, but they operate primarily on the logical and SOAP protocol-level messages, which can sometimes be resource-intensive due to DOM parsing.
  • CXF Interceptors (High Performance): Specific to Apache CXF. They operate on a pipeline architecture with phase-based execution (e.g., RECEIVE, PRE_STREAM, WRITE). Interceptors can manipulate raw bytes, XML streams, or Java objects directly, making them much faster and more flexible than standard handlers, though they lock your client or server code to Apache CXF.

Configuring Timeouts and Debugging

In production environments, setting timeouts on SOAP client calls is critical to prevent hung threads. You can configure HTTP timeouts programmatically on a JAX-WS client using standard Jakarta EE request context properties, or fall back to Apache CXF-specific configurations for fine-grained control.

Standard Jakarta JAX-WS Timeout Configuration:

import jakarta.xml.ws.BindingProvider;
import java.util.Map;

BindingProvider bp = (BindingProvider) client;
Map<String, Object> requestContext = bp.getRequestContext();

// Set connection timeout in milliseconds
requestContext.put("jakarta.xml.ws.client.connectionTimeout", 5000);
// Set receive timeout in milliseconds
requestContext.put("jakarta.xml.ws.client.receiveTimeout", 10000);

Apache CXF-Specific Timeout Configuration:

import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;

org.apache.cxf.endpoint.Client cxfClient = ClientProxy.getClient(client);
HTTPConduit conduit = (HTTPConduit) cxfClient.getConduit();
HTTPClientPolicy policy = new HTTPClientPolicy();

policy.setConnectionTimeout(5000); // 5 seconds
policy.setReceiveTimeout(10000);    // 10 seconds
conduit.setClient(policy);

Securing Your SOAP Web Services

Never recommend or use Basic Authentication over plain, unencrypted HTTP. Always enforce transport-level security (HTTPS/TLS) or apply WS-Security for message-level encryption and signing.

Enforcing HTTPS

To mandate HTTPS transport, secure your WildFly Undertow listener with an SSL/TLS Elytron keystore and define security constraints in your web.xml:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>SecureServices</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>

WS-Security (WSS4J)

For message-level security (e.g., WS-UsernameToken, digital signatures, or XML encryption), configure Apache CXF on WildFly with WSS4J interceptors. This ensures messages remain encrypted and verified even when passing through intermediate proxies and API Gateways.

Cloud Deployment: Kubernetes, OpenShift, and Reverse Proxies

When deploying SOAP applications into cloud container platforms (like Kubernetes or Red Hat OpenShift) behind a reverse proxy (e.g., NGINX, HAProxy, or an Ingress controller), the WSDL file generated by the server might default to internal container IPs or HTTP ports, breaking external clients.

To resolve this, configure WildFly's webservices subsystem to rewrite the WSDL host and port dynamically to match your external-facing gateway. Execute the following management CLI commands:

/subsystem=webservices:write-attribute(name=wsdl-host, value="api.yourcompany.com")
/subsystem=webservices:write-attribute(name=wsdl-port, value=443)
/subsystem=webservices:write-attribute(name=wsdl-secure-port, value=443)
/subsystem=webservices:write-attribute(name=wsdl-uri-scheme, value="https")
reload

Testing Your Endpoints

Modern developers should move away from obsolete IDE-integrated wizards. For testing SOAP endpoints, use standard external tools or automated JUnit 5 test cases:

  • SoapUI / Postman: Import your WSDL URL (e.g., https://api.yourcompany.com/balance/MathWS?wsdl) to automatically generate valid SOAP envelopes, execute requests, and inspect raw responses.
  • curl: You can quickly send a SOAP request payload via command line:
    curl -X POST -H "Content-Type: text/xml; charset=utf-8" \
      -d '<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sam="http://sample.com/"><soapenv:Header/><soapenv:Body><sam:sum><arg0>10</arg0><arg1>20</arg1></sam:sum></soapenv:Body></soapenv:Envelope>' \
      https://api.yourcompany.com/balance/MathWS

Recommended Articles

How to develop CXF Web services with JBoss / WildFly

Learn how to develop, deploy, and secure SOAP Web Services on WildFly 41.0.1.Final using Jakarta EE 11 and Apache CXF. Master JAX-WS handlers, CXF interceptors, and robust cloud configurations.

Apache CXF Interceptors on WildFly 41 and Jakarta EE 11

Learn how to write, configure, and customize Apache CXF Interceptors on WildFly 41.0.1.Final and Jakarta EE 11. Upgrade from legacy configuration to modern Jakarta XML Web Services.

How to test SOAP Web Services - WildFly 41 & Jakarta EE 11

Master SOAP Web Services testing under Jakarta EE 11 and WildFly 41. Learn programmatic unit testing, Apache CXF interceptor config, and tool integrations with SoapUI, JMeter, and cURL.

Using Axis Web Services with JBoss: Migration to modern JAX-WS with WildFly 41

Learn how to migrate legacy Apache Axis SOAP web services from JBoss to modern Jakarta EE 11 and JAX-WS on WildFly 41.0.1.Final using Apache CXF with secure HTTPS configurations and debugging.