Apache Axis: Legacy SOAP Framework Migration
Apache Axis (and its successor Axis2) powered a generation of SOAP-based web services in the Java ecosystem. While these frameworks served their purpose well, many organizations now face the challenge of maintaining aging Axis deployments that carry security risks, dependency conflicts, and diminishing community support.
This post examines the realities of migrating away from Apache Axis and provides a practical migration strategy.
Why Migrate?
Apache Axis 1.x reached end-of-life years ago, and even Axis2 has seen declining activity. Common motivations for migration include:
-
Security vulnerabilities: Older Axis versions have unpatched CVEs, and the dependency chain (older versions of
commons-*, XML parsers) introduces additional risk. - Java version compatibility: Axis 1.x struggles on modern JDKs (11, 17, 21) due to removed internal APIs and JAXB/JAX-WS module changes.
- Maintainability: Generated stubs and WSDL2Java artifacts are brittle and hard to evolve.
- Ecosystem gravity: Modern frameworks (Spring Boot, JAX-WS RI, Apache CXF) offer better tooling and observability.
Assessing Your Current Deployment
Before writing any code, inventory what you have.
# Find Axis dependencies across a multi-module project
find . -name "pom.xml" -exec grep -l "axis" {} \;
# Identify generated stub packages
grep -r "org.apache.axis" --include="*.java" src/ | wc -l
Document the following:
| Aspect | Questions to Answer |
|---|---|
| Contracts | Do you have canonical WSDL/XSD files? |
| Bindings | Document/literal or RPC/encoded? |
| Handlers | Custom SOAP handlers for security/logging? |
| Transport | HTTP only, or JMS/other? |
| Clients | Who consumes these services externally? |
Warning: RPC/encoded bindings are not WS-I compliant and are poorly supported by modern frameworks. Plan to migrate these to document/literal.
Choosing a Target Framework
The two most common migration targets are Apache CXF and JAX-WS RI (Metro). CXF is generally recommended for its Spring integration, active maintenance, and flexible configuration.
<!-- Apache CXF core dependencies -->
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxws</artifactId>
<version>4.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http</artifactId>
<version>4.0.4</version>
</dependency>
Migration Strategy: Contract-First
The safest migration preserves your existing WSDL contract so external clients require no changes. This is a contract-first approach.
Step 1: Extract the Canonical WSDL
If you only have Axis-generated stubs, retrieve the published WSDL from the running service:
curl "http://legacy-host:8080/services/OrderService?wsdl" -o OrderService.wsdl
Clean up any Axis-specific namespace quirks and validate against WS-I Basic Profile.
Step 2: Generate CXF Artifacts
Use the CXF wsdl2java tool to regenerate client and server-side code:
wsdl2java -d src/generated -impl -server \
-p com.example.orders \
OrderService.wsdl
Wire this into your build for reproducibility:
<plugin>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-codegen-plugin</artifactId>
<version>4.0.4</version>
<executions>
<execution>
<id>generate-sources</id>
<phase>generate-sources</phase>
<configuration>
<wsdlOptions>
<wsdlOption>
<wsdl>${basedir}/src/main/resources/OrderService.wsdl</wsdl>
</wsdlOption>
</wsdlOptions>
</configuration>
<goals>
<goal>wsdl2java</goal>
</goals>
</execution>
</executions>
</plugin>
Step 3: Reimplement the Service Endpoint
Move your business logic into a clean JAX-WS annotated implementation. The generated SEI (Service Endpoint Interface) enforces contract fidelity.
@WebService(
endpointInterface = "com.example.orders.OrderPortType",
targetNamespace = "http://example.com/orders",
serviceName = "OrderService"
)
public class OrderServiceImpl implements OrderPortType {
private final OrderRepository repository;
public OrderServiceImpl(OrderRepository repository) {
this.repository = repository;
}
@Override
public OrderResponse getOrder(OrderRequest request) {
// Business logic migrated from the old Axis skeleton
Order order = repository.findById(request.getOrderId());
OrderResponse response = new OrderResponse();
response.setStatus(order.getStatus());
response.setTotal(order.getTotal());
return response;
}
}
Step 4: Publish the Endpoint
With Spring Boot and CXF, endpoint publishing is declarative:
java
@Configuration
public class WebServiceConfig {
@Bean
public ServletR
Top comments (0)