Apache Axis2 Spring Boot Starter

axis2-spring-boot-starter reduces Axis2 + Spring Boot integration from a multi-day configuration project to a single Maven dependency. It handles servlet registration, repository configuration, and OpenAPI/MCP endpoint activation with sensible defaults — for both SOAP and JSON-RPC services.

What Axis2 brings to Spring Boot

  • Large JSON streaming (10MB–1GB+) — the streaming JSON formatter flushes HTTP/2 DATA frames every 64KB, keeping server memory flat regardless of response size. No reactive stack required.
  • Native HTTP/2 with backpressure — the H2TransportSender provides connection multiplexing, flow control, and ALPN negotiation as a drop-in transport layer. See also the HTTP/2 overview.
  • AI-ready services (MCP) — Axis2 auto-generates an MCP tool catalog from deployed services. AI assistants discover and call your services as tools without hand-authored definitions. See MCP examples for live demos.
  • Response field selection — the ?fields= query parameter lets clients request only the fields they need, reducing payload size and AI token consumption at the serialization layer with zero application code.
  • OpenAPI schemas from Hibernate mappings — the JPA/Hibernate schema generator produces read and write JSON Schemas directly from @Entity annotations or .hbm.xml files, including a batch CLI tool for large codebases. No hand-authored API contracts — the schema stays in sync with the database model by construction.
  • Built-in pagination — the PaginatedResponse wrapper provides offset/limit pagination with server-enforced safety limits, totalCount for page controls, and hasMore for infinite scroll — mapping directly to JPA/Hibernate's setFirstResult/setMaxResults.
  • SOAP + JSON from the same services — serve both SOAP/XML and JSON-RPC from the same Spring beans, selected by configuration. Useful for enterprises maintaining both legacy and modern clients.

This starter supports both WAR deployment to an external container (Tomcat 11, WildFly 32/39) and embedded Tomcat for local development. For embedded mode, set axis2.repo in application.properties to the exploded WAR directory from your build. See Deployment Model for details.

0. Deployment Model

Axis2 supports two Spring Boot deployment modes:

Mode How Use Case
External container (WAR) Package as WAR, deploy to Tomcat 11 or WildFly 32+ Production — the recommended deployment model
Embedded Tomcat mvn spring-boot:run -Pembedded Local development and testing

External container (production)

For production, deploy as a WAR to an external servlet container. Your Spring Boot application must extend SpringBootServletInitializer and be packaged as a WAR. External containers provide operational advantages for long-running Axis2 deployments:

  • Container-managed TLS, thread pools, and connection pools
  • Hot-redeploy via exploded WAR without JVM restart
  • Central certificate management (Tomcat's server.xml, WildFly's Elytron)
  • HTTP/2 with ALPN (via container connector, not application code)

Embedded Tomcat (development)

For local development and testing, the sample application supports Spring Boot's embedded Tomcat via a Maven profile. Axis2's WarBasedAxisConfigurator requires a filesystem layout (WEB-INF/conf/axis2.xml, WEB-INF/services/*.aar, WEB-INF/modules/*.mar) that embedded Tomcat does not provide from its temp docbase. The -Daxis2.repo system property tells the configurator where to find the exploded WAR from the build:

# Build first (creates the exploded WAR with services and modules)
mvn clean install -DskipTests

# Run with embedded Tomcat
mvn spring-boot:run -Pembedded \
  -Dspring-boot.run.arguments="--server.port=9090" \
  -Dspring-boot.run.jvmArguments="-Daxis2.repo=target/deploy/axis2-json-api/WEB-INF"

The sample application requires authentication. Log in first to obtain a token, then pass it as a Bearer token on subsequent requests:

# 1. Log in (sample credentials)
TOKEN=$(curl -s http://localhost:9090/services/loginService \
  -H 'Content-Type: application/json' \
  -d '{"doLogin":[{"arg0":{"email":"java-dev@axis.apache.org","credentials":"userguide"}}]}' \
  | python3 -c "import sys,json; print(json.load(sys.stdin)['response']['token'])")

# 2. Call a service with the token
curl -s http://localhost:9090/services/FinancialBenchmarkService \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $TOKEN" \
  -d '{"portfolioVariance":[{"arg0":{"weights":[0.5,0.5],"covarianceMatrix":[[0.04,0.006],[0.006,0.09]]}}]}'

OpenAPI and MCP endpoints do not require authentication:

curl -s http://localhost:9090/openapi.json
curl -s http://localhost:9090/openapi-mcp.json

For production, external containers remain the recommended deployment:

  • Container-managed thread pools, connection pools, and monitoring (Actuator/Micrometer)
  • Hot-redeploy via exploded WAR without JVM restart
  • Central TLS/certificate management (Tomcat's server.xml, WildFly's Elytron)
  • Established operational tooling (WildFly CLI, Tomcat Manager, deployment scanners)

Which external containers?

Container JDK Tested
Apache Tomcat 11 OpenJDK 17, 21, 25 Yes (21/25 live-tested; 17 is the minimum supported by Tomcat 11 and Spring Boot 3.x)
WildFly 32 OpenJDK 17, 21 Yes (production-tested on WildFly 32 + OpenJDK 17)
WildFly 39 OpenJDK 21, 25 Yes (live-tested with OpenJDK 25)

Minimum JDK version: OpenJDK 17. Axis2 core and the starter compile and pass CI tests with -Dmaven.compiler.release=17. Spring Boot 3.x and Tomcat 11 both require Java 17 as a minimum. The sample applications target Java 21 source level but Axis2 itself imposes no version above 17.

Other Jakarta EE 9+ containers (WebSphere Liberty, Payara) should work but are not tested.

Embedded mode limitations

Embedded Tomcat requires a pre-built exploded WAR on the filesystem (pointed to by axis2.repo). This means you must run mvn install before mvn spring-boot:run so that the .aar service archives and axis2.xml are staged in the build output directory. Changes to service metadata (operations, message receivers, MCP descriptions) require a rebuild.

Note that the service code itself is a Spring @Component bean on the classpath — the .aar file contains only metadata (services.xml) that tells Axis2 which Spring bean to call, which operations to expose, and which message receivers to use. The SpringBeanName parameter in services.xml bridges Axis2 service dispatch to Spring's application context. A future improvement could scan for services.xml resources on the classpath, eliminating the filesystem requirement entirely.

1. Quick Start

Add the starter to your pom.xml:

<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-spring-boot-starter</artifactId>
    <version>2.0.1</version>
</dependency>

<!-- Optional: OpenAPI/MCP endpoints -->
<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-openapi</artifactId>
    <version>2.0.1</version>
</dependency>

This single dependency replaces ~30 individual Axis2 dependencies (axis2-kernel, axis2-transport-http, axis2-json, axis2-spring, axis2-jaxws, etc.) and eliminates the need for a hand-coded Axis2WebAppInitializer or OpenApiServlet class.

The starter auto-registers AxisServlet at /services/*. If you also add the optional axis2-openapi dependency (shown above), the starter additionally registers endpoints for OpenAPI spec generation (/openapi.json), Swagger UI (/swagger-ui), and MCP tool discovery (/openapi-mcp.json). See Section 7 for details.

2. How AxisServlet Works (SOAP vs JSON)

org.apache.axis2.transport.http.AxisServlet is the single entry point for all Axis2 service calls — SOAP and JSON-RPC alike. The servlet itself is protocol-agnostic. It does not know or care whether the incoming request is SOAP 1.1, SOAP 1.2, or JSON-RPC.

The protocol handling is determined entirely by axis2.xml:

Component SOAP JSON-RPC
Message Receivers
Parse the incoming payload and invoke the service method
RawXMLINOutMessageReceiver
RawXMLINOnlyMessageReceiver
(read SOAP XML envelopes)
JsonRpcMessageReceiver
JsonInOnlyRPCMessageReceiver
(read JSON-RPC {"op":[{"arg0":{}}]} envelope)
Dispatchers
Route the request to the correct service and operation
Multi-handler chain:
SOAPActionBasedDispatcher
RequestURIBasedDispatcher
SOAPMessageBodyBasedDispatcher
HTTPLocationBasedDispatcher
(routes by SOAPAction header, WS-Addressing, message body)
Single handler:
JSONBasedDefaultDispatcher
(routes by URL path only)
enableJSONOnly false (the default since Axis2 1.0, 2006) true (skips SOAP envelope processing)

SOAP and JSON cannot coexist in a single deployment. The message receivers and dispatchers are incompatible — a SOAP receiver cannot parse JSON, and the JSON dispatcher cannot route by SOAPAction. This is not a starter limitation; it is how Axis2's processing pipeline works.

AxisServlet Initialization Sequence

When AxisServlet starts (init()), it:

  1. Creates a WarBasedAxisConfigurator
  2. Locates the repository (WEB-INF/) using, in order:
    1. axis2.repository.path servlet init-parameter (if set explicitly)
    2. axis2.repository.url servlet init-parameter (if set explicitly)
    3. ServletContext.getRealPath("/WEB-INF") (automatic fallback)
  3. Reads WEB-INF/conf/axis2.xml to configure the engine
  4. Scans WEB-INF/services/*.aar to deploy services
  5. Scans WEB-INF/modules/*.mar to load modules (e.g., OpenAPI)
  6. Stores the ConfigurationContext in the ServletContext — this is how other servlets (OpenAPI, MCP) access the Axis2 engine

The starter sets axis2.repository.path eagerly at startup as a workaround for WildFly VFS timing issues where getRealPath() can return null during lazy servlet initialization.

3. Configuration Properties

Property Default Description
axis2.enabled true Set to false to disable Axis2 entirely (e.g., for server roles that don't serve web services)
axis2.mode json soap or json — selects the built-in axis2.xml template (see Section 4)
axis2.services-path /services URL path for AxisServlet. Servlet is registered at {services-path}/*
axis2.configuration-file (empty) Path to a custom axis2.xml. Overrides axis2.mode. Supports classpath: prefix
axis2.openapi.enabled true Register OpenAPI/MCP servlet (requires axis2-openapi on classpath)
axis2.openapi.paths /openapi.json, /openapi.yaml, /swagger-ui, /openapi-mcp.json URL paths for OpenAPI endpoints

4. SOAP Mode vs JSON Mode

The starter ships two built-in axis2.xml templates, selected by axis2.mode:

JSON mode (axis2.mode=json, the default)

# application.properties
axis2.mode=json

Uses JsonRpcMessageReceiver, JSONBasedDefaultDispatcher, and enableJSONOnly=true. Choose this for new services, MCP/AI integration, and REST/OpenAPI consumers.

SOAP mode (axis2.mode=soap)

# application.properties
axis2.mode=soap

Uses RawXMLINOutMessageReceiver, the full SOAP dispatcher stack, and enableJSONOnly=false. Choose this for WSDL-first services, WS-Security, WS-Addressing, or interop with .NET/PHP SOAP clients. This is the classic Axis2 configuration that has been in use since version 1.0 (2006).

Custom axis2.xml

# application.properties
axis2.configuration-file=classpath:my-axis2.xml

Overrides both built-in templates. Use this when you need custom phases, modules, transport configurations, or any axis2.xml settings not covered by the built-in templates.

The starter only stages axis2.xml if WEB-INF/conf/axis2.xml does not already exist. If your Maven build pre-stages it (e.g., via maven-antrun-plugin), the starter will not overwrite it.

5. What Gets Autoconfigured

Component What it replaces Condition
AxisServlet registration at /services/* Hand-coded Axis2WebAppInitializer Always (when axis2.enabled=true)
axis2.xml staging (SOAP or JSON template) axis2.xml copy step in maven-antrun-plugin When WEB-INF/conf/axis2.xml does not already exist
OpenAPI/MCP servlet at /openapi.json, /swagger-ui, /openapi-mcp.json Hand-coded OpenApiServlet class When axis2-openapi is on classpath and axis2.openapi.enabled=true

6. What Stays in Your Application

The starter deliberately does not autoconfigure:

  • Security — JWT authentication, mTLS, SAML, CSRF guard filter chains are application-specific. The starter does not provide any SecurityFilterChain beans.
  • Service definitionsservices.xml files inside .aar archives define operation names, Spring bean names, per-operation message receivers. These are service-specific.
  • .aar file creation — pre-built .aar files must be staged in WEB-INF/services/ by the Maven build (maven-antrun-plugin or axis2-aar-maven-plugin).
  • .mar module staging — the OpenAPI module JAR must be renamed to .mar and placed in WEB-INF/modules/ by the Maven build.
  • Container-specific descriptors — WildFly's jboss-deployment-structure.xml, jboss-web.xml, beans.xml.
  • @SpringBootApplication class — the consuming app still needs its main class extending SpringBootServletInitializer.

7. OpenAPI and MCP Support

axis2-openapi is a separate Axis2 module (Maven artifact: org.apache.axis2:axis2-openapi) that auto-generates an OpenAPI 3.0.1 specification and MCP (Model Context Protocol) tool catalog from your deployed Axis2 services. OpenAPI is a standard format for describing REST APIs — tools like Swagger UI use it to generate interactive documentation. MCP is a protocol that lets AI assistants (Claude, ChatGPT, etc.) discover and call your services as tools.

The module auto-generates both from your deployed Axis2 services. It reads each service's services.xml (inside the .aar file) at runtime — specifically the operation names, message receiver types, and MCP metadata parameters — and produces the specification automatically. No annotations on your service code are needed.

How it works with the starter: The starter detects axis2-openapi on the classpath via Spring Boot's @ConditionalOnClass(OpenApiModule.class) and automatically registers a servlet that delegates to Axis2's SwaggerUIHandler. No additional code is needed in your application.

To enable it, add the dependency to your pom.xml:

<dependency>
    <groupId>org.apache.axis2</groupId>
    <artifactId>axis2-openapi</artifactId>
    <version>2.0.1</version>
</dependency>

Your Maven build must also copy the axis2-openapi JAR as a .mar (Module Archive) into WEB-INF/modules/ so the Axis2 engine can load it:

<!-- In maven-antrun-plugin, prepare-package phase -->
<copy file="${settings.localRepository}/org/apache/axis2/axis2-openapi/${axis2.version}/axis2-openapi-${axis2.version}.jar"
      tofile="${project.build.directory}/${project.build.finalName}/WEB-INF/modules/openapi-${axis2.version}.mar"
      overwrite="true"/>

Once deployed, the following endpoints are available (no auth required):

  • GET /openapi.json — OpenAPI 3.0.1 specification (JSON)
  • GET /openapi.yaml — same in YAML format
  • GET /swagger-ui — interactive Swagger UI
  • GET /openapi-mcp.json — MCP tool catalog for AI assistants (includes operation names, input schemas, and payload templates)

The MCP catalog is generated from services.xml parameters like mcpDescription and mcpInputSchema. See the JSON-RPC MCP Integration Guide for the full catalog format and how AI assistants discover and call Axis2 services.

8. Migration from Manual Configuration

If you have an existing Axis2 + Spring Boot project with manual servlet registration, follow these steps:

  1. Replace dependencies: Remove the ~30 individual Axis2 dependencies and add the single axis2-spring-boot-starter dependency.
  2. Delete Axis2WebAppInitializer (or your equivalent ServletContextInitializer that registers AxisServlet). The starter handles this.
  3. Delete OpenApiServlet.java if you have one. The starter provides it when axis2-openapi is on the classpath.
  4. Set axis2.mode in application.properties: json for JSON-RPC services, soap for SOAP services.
  5. Keep your Maven build steps that create .aar files and copy .mar modules — the starter does not replace these yet.
  6. Keep your security configuration — the starter does not touch Spring Security.

For working reference implementations, see:

  • modules/samples/userguide/src/userguide/springbootdemo-tomcat11/README.md
  • modules/samples/userguide/src/userguide/springbootdemo-wildfly/README.md

9. Tested Configurations

JSON-RPC / MCP (axis2.mode=json)

The starter was tested with the springbootdemo-tomcat11 sample application, replacing ~30 individual Axis2 dependencies with the single axis2-spring-boot-starter dependency and removing the hand-coded Axis2WebAppInitializer. All endpoints confirmed working over HTTPS/HTTP2 on Tomcat 11 with OpenJDK 25:

Endpoint Result
GET /openapi.json Pass — OpenAPI 3.0.1 spec returned
GET /openapi.yaml Pass
GET /openapi-mcp.json Pass — MCP tool catalog with full inputSchema
GET /swagger-ui Pass — HTTP 200
POST loginService/doLogin Pass — JWT token returned
POST FinancialBenchmarkService/portfolioVariance Pass — SUCCESS, variance=0.03168
POST FinancialBenchmarkService/monteCarlo Pass — SUCCESS, 10K simulations
POST FinancialBenchmarkService/scenarioAnalysis Pass — SUCCESS

SOAP (axis2.mode=soap)

The SOAP axis2.xml template was validated by unit tests confirming correct message receivers (RawXMLINOutMessageReceiver, RawXMLINOnlyMessageReceiver), the full SOAP dispatcher stack (SOAPActionBasedDispatcher, RequestURIBasedDispatcher, SOAPMessageBodyBasedDispatcher, HTTPLocationBasedDispatcher), and enableJSONOnly=false. The SOAP template is based on the Axis2 configuration that has been in production since version 1.0 (2006) and is identical in structure to the configuration used by the legacy userguide example1 Echo service (MyService.echo() with RawXMLINOutMessageReceiver).

Unit test suite

The starter includes 9 unit tests covering:

  • Both axis2.xml templates exist on the classpath
  • JSON template correctness (enableJSONOnly=true, JSONBasedDefaultDispatcher, no SOAP receivers)
  • SOAP template correctness (enableJSONOnly=false, RawXMLINOut receivers, full SOAP dispatcher stack, no JSON dispatcher)
  • Default property values
  • AutoConfiguration.imports contains all required classes

Container matrix

See Section 0 for the full container compatibility matrix covering WAR deployment (Tomcat 11, WildFly 32/39) and embedded Tomcat for local development.

10. HTTP/2 and Streaming

Axis2/Java has built-in HTTP/2 support at the serialization layer, not just the transport layer. Unlike most frameworks where the servlet container handles HTTP/2 transparently and the serialization is unaware of the protocol, Axis2 integrates HTTP/2 awareness into the JSON message formatter pipeline:

  • Dedicated HTTP/2 transport module (modules/transport-h2) — ALPN negotiation, per-stream flow control, adaptive buffering, compression optimization, and HTTP/1.1 fallback. See HTTP/2 Integration Guide.
  • Streaming JSON formatters — flush every 64 KB during serialization, converting a single buffered response into a stream of HTTP/2 DATA frames. A 50MB response arrives at the client as ~780 incremental frames, with the first frame arriving within milliseconds. See Streaming JSON Formatter.
  • Field selection — callers add ?fields=status,result to any service URL and the response includes only those fields, filtered during serialization with zero overhead when not used. See Field Selection.
  • C parity — the same streaming architecture exists in Axis2/C via Apache httpd mod_h2. Both implementations use the same 64 KB flush interval, producing identical HTTP/2 DATA frame patterns.

For a detailed comparison of Axis2's HTTP/2 architecture with Spring MVC, JAX-RS, gRPC, and other frameworks, see the framework comparison in the HTTP/2 Integration Guide.