Full Stack • Java • System Design • Cloud • AI Engineering

Web Services2026-06-17

SOAP Web Services

Master SOAP web services with visual diagrams covering WSDL, JAX-WS, contract-first vs contract-last, SOAP message structure, and complete implementation examples

SOAP (Simple Object Access Protocol) is an XML-based protocol for exchanging structured information in web services. Understanding SOAP architecture, WSDL, and JAX-WS is essential for enterprise integration.

SOAP Architecture Stack

graph TB
    A[Service Discovery - UDDI] --> B[Service Description - WSDL]
    B --> C[XML Messaging - SOAP]
    C --> D[Service Transport - HTTP/SMTP/FTP]
    
    A1[Find Services] --> A
    B1[Define Interface] --> B
    C1[Message Format] --> C
    D1[Network Protocol] --> D
    
    style A fill:#FF9800
    style B fill:#4CAF50
    style C fill:#2196F3
    style D fill:#9C27B0

Key Points:

  • Transport Layer: HTTP, SMTP, FTP for message delivery
  • Messaging Layer: SOAP for XML message format
  • Description Layer: WSDL defines service interface
  • Discovery Layer: UDDI for service registry
  • Protocol Stack: Each layer builds on the previous

SOAP Message Structure

<!-- SOAP Request -->
POST /PriceService HTTP/1.1
Host: www.example.com
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 350

<?xml version="1.0"?>
<soap:Envelope 
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
    xmlns:m="http://www.example.com/prices">
    
    <!-- Optional Header -->
    <soap:Header>
        <m:Authentication>
            <m:Username>user123</m:Username>
            <m:Password>pass456</m:Password>
        </m:Authentication>
    </soap:Header>
    
    <!-- Required Body -->
    <soap:Body>
        <m:GetPrice>
            <m:Item>PlasmaTV</m:Item>
            <m:Category>Electronics</m:Category>
        </m:GetPrice>
    </soap:Body>
</soap:Envelope>

<!-- SOAP Response -->
HTTP/1.1 200 OK
Content-Type: application/soap+xml; charset=utf-8
Content-Length: 280

<?xml version="1.0"?>
<soap:Envelope 
    xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
    xmlns:m="http://www.example.com/prices">
    
    <soap:Body>
        <m:GetPriceResponse>
            <m:Price currency="USD">3500.00</m:Price>
            <m:Availability>In Stock</m:Availability>
        </m:GetPriceResponse>
    </soap:Body>
</soap:Envelope>

Contract-First vs Contract-Last

flowchart TB
    subgraph "Contract-First Approach"
        A1[Define XSD Schema] --> A2[Define WSDL]
        A2 --> A3[Generate Java Classes]
        A3 --> A4[Implement Service]
        A4 --> A5[Deploy]
    end
    
    subgraph "Contract-Last Approach"
        B1[Write Java Classes] --> B2[Add Annotations]
        B2 --> B3[Generate WSDL]
        B3 --> B4[Deploy]
    end
    
    style A2 fill:#4CAF50
    style B3 fill:#FF9800

Key Points:

  • Contract-First: Define WSDL/XSD first, generate Java code
  • Contract-Last: Write Java code first, generate WSDL
  • Best Practice: Contract-first for loose coupling and control
  • Flexibility: Contract-first allows independent client/server development
  • Maintenance: Contract-first easier to version and maintain

Contract-First Implementation

// 1. Define XSD Schema (customer.xsd)
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
           targetNamespace="http://example.com/customer"
           xmlns:tns="http://example.com/customer">
    
    <xs:element name="GetCustomerRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="customerId" type="xs:long"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    
    <xs:element name="GetCustomerResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="customer" type="tns:Customer"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>
    
    <xs:complexType name="Customer">
        <xs:sequence>
            <xs:element name="id" type="xs:long"/>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="email" type="xs:string"/>
        </xs:sequence>
    </xs:complexType>
</xs:schema>

// 2. Generate Java classes using JAXB
// mvn jaxb2:xjc

// 3. Implement Service Endpoint
@WebService(serviceName = "CustomerService",
            portName = "CustomerPort",
            targetNamespace = "http://example.com/customer")
public class CustomerServiceImpl {
    
    @Autowired
    private CustomerRepository customerRepository;
    
    @WebMethod(operationName = "getCustomer")
    @WebResult(name = "GetCustomerResponse")
    public GetCustomerResponse getCustomer(
            @WebParam(name = "GetCustomerRequest") 
            GetCustomerRequest request) {
        
        Long customerId = request.getCustomerId();
        Customer customer = customerRepository.findById(customerId);
        
        GetCustomerResponse response = new GetCustomerResponse();
        response.setCustomer(customer);
        
        return response;
    }
}

// 4. Spring Configuration
@Configuration
@EnableWs
public class WebServiceConfig extends WsConfigurerAdapter {
    
    @Bean
    public ServletRegistrationBean<MessageDispatcherServlet> 
            messageDispatcherServlet(ApplicationContext context) {
        
        MessageDispatcherServlet servlet = 
            new MessageDispatcherServlet();
        servlet.setApplicationContext(context);
        servlet.setTransformWsdlLocations(true);
        
        return new ServletRegistrationBean<>(servlet, "/ws/*");
    }
    
    @Bean(name = "customers")
    public DefaultWsdl11Definition defaultWsdl11Definition(
            XsdSchema customersSchema) {
        
        DefaultWsdl11Definition wsdl11Definition = 
            new DefaultWsdl11Definition();
        wsdl11Definition.setPortTypeName("CustomerPort");
        wsdl11Definition.setLocationUri("/ws");
        wsdl11Definition.setTargetNamespace("http://example.com/customer");
        wsdl11Definition.setSchema(customersSchema);
        
        return wsdl11Definition;
    }
    
    @Bean
    public XsdSchema customersSchema() {
        return new SimpleXsdSchema(
            new ClassPathResource("customer.xsd"));
    }
}

Contract-Last Implementation

// 1. Write Java Classes with Annotations
@WebService(name = "CustomerService",
            serviceName = "CustomerWebService",
            targetNamespace = "http://example.com/customer")
@SOAPBinding(style = SOAPBinding.Style.DOCUMENT,
             use = SOAPBinding.Use.LITERAL)
public class CustomerServiceImpl {
    
    @WebMethod(operationName = "getCustomer")
    @WebResult(name = "customer")
    public Customer getCustomer(
            @WebParam(name = "customerId") Long customerId) {
        
        // Business logic
        Customer customer = new Customer();
        customer.setId(customerId);
        customer.setName("John Doe");
        customer.setEmail("[email protected]");
        
        return customer;
    }
    
    @WebMethod(operationName = "createCustomer")
    @WebResult(name = "customerId")
    public Long createCustomer(
            @WebParam(name = "customer") Customer customer) {
        
        // Save customer
        return 123L;
    }
}

// 2. Customer POJO
@XmlRootElement(name = "customer")
@XmlAccessorType(XmlAccessType.FIELD)
public class Customer {
    
    @XmlElement(required = true)
    private Long id;
    
    @XmlElement(required = true)
    private String name;
    
    @XmlElement(required = true)
    private String email;
    
    // Getters and setters
}

// 3. Publish Service
public class ServicePublisher {
    
    public static void main(String[] args) {
        String url = "http://localhost:8080/ws/customer";
        Endpoint.publish(url, new CustomerServiceImpl());
        System.out.println("Service published at: " + url);
    }
}

// 4. WSDL automatically generated at:
// http://localhost:8080/ws/customer?wsdl

WSDL Structure

graph TB
    A[WSDL Document] --> B[Types]
    A --> C[Message]
    A --> D[PortType]
    A --> E[Binding]
    A --> F[Service]
    
    B --> B1[XSD Schema<br/>Data Types]
    C --> C1[Input/Output<br/>Messages]
    D --> D1[Operations<br/>Abstract Interface]
    E --> E1[Protocol Binding<br/>SOAP/HTTP]
    F --> F1[Endpoint<br/>URL Location]
    
    style D fill:#4CAF50
    style E fill:#FF9800

Key Points:

  • Types: Data type definitions using XSD
  • Message: Input and output message definitions
  • PortType: Abstract operations (like Java interface)
  • Binding: Protocol and data format specifications
  • Service: Endpoint location (URL)

WSDL Example

<?xml version="1.0" encoding="UTF-8"?>
<definitions name="CustomerService"
             targetNamespace="http://example.com/customer"
             xmlns="http://schemas.xmlsoap.org/wsdl/"
             xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
             xmlns:tns="http://example.com/customer"
             xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    
    <!-- Types: Data type definitions -->
    <types>
        <xsd:schema targetNamespace="http://example.com/customer">
            <xsd:element name="GetCustomerRequest">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="customerId" type="xsd:long"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            
            <xsd:element name="GetCustomerResponse">
                <xsd:complexType>
                    <xsd:sequence>
                        <xsd:element name="customer" type="tns:Customer"/>
                    </xsd:sequence>
                </xsd:complexType>
            </xsd:element>
            
            <xsd:complexType name="Customer">
                <xsd:sequence>
                    <xsd:element name="id" type="xsd:long"/>
                    <xsd:element name="name" type="xsd:string"/>
                    <xsd:element name="email" type="xsd:string"/>
                </xsd:sequence>
            </xsd:complexType>
        </xsd:schema>
    </types>
    
    <!-- Messages: Input and output -->
    <message name="GetCustomerRequest">
        <part name="parameters" element="tns:GetCustomerRequest"/>
    </message>
    
    <message name="GetCustomerResponse">
        <part name="parameters" element="tns:GetCustomerResponse"/>
    </message>
    
    <!-- PortType: Operations (Abstract interface) -->
    <portType name="CustomerPortType">
        <operation name="getCustomer">
            <input message="tns:GetCustomerRequest"/>
            <output message="tns:GetCustomerResponse"/>
        </operation>
    </portType>
    
    <!-- Binding: Protocol specification -->
    <binding name="CustomerBinding" type="tns:CustomerPortType">
        <soap:binding transport="http://schemas.xmlsoap.org/soap/http"/>
        <operation name="getCustomer">
            <soap:operation soapAction="getCustomer"/>
            <input>
                <soap:body use="literal"/>
            </input>
            <output>
                <soap:body use="literal"/>
            </output>
        </operation>
    </binding>
    
    <!-- Service: Endpoint location -->
    <service name="CustomerService">
        <port name="CustomerPort" binding="tns:CustomerBinding">
            <soap:address location="http://localhost:8080/ws/customer"/>
        </port>
    </service>
</definitions>

WSDL Operation Types

// 1. One-Way: Receive message, no response
@WebMethod
@Oneway
public void logEvent(@WebParam(name = "event") Event event) {
    eventLogger.log(event);
    // No return value
}

// 2. Request-Response: Most common, receive and respond
@WebMethod
public Customer getCustomer(@WebParam(name = "id") Long id) {
    return customerService.findById(id);
}

// 3. Solicit-Response: Send request, wait for response (server-initiated)
// Less common, typically used in async scenarios

// 4. Notification: Send message, no response expected
@WebMethod
@Oneway
public void sendNotification(@WebParam(name = "message") String message) {
    notificationService.send(message);
}

JAX-WS Client Implementation

// 1. Generate client stubs from WSDL
// wsimport -keep -s src http://localhost:8080/ws/customer?wsdl

// 2. Use generated client
public class CustomerClient {
    
    public static void main(String[] args) {
        // Create service
        CustomerWebService service = new CustomerWebService();
        
        // Get port
        CustomerService port = service.getCustomerPort();
        
        // Call web service method
        Customer customer = port.getCustomer(123L);
        
        System.out.println("Customer: " + customer.getName());
        System.out.println("Email: " + customer.getEmail());
    }
}

// 3. Spring Integration
@Configuration
public class WebServiceClientConfig {
    
    @Bean
    public Jaxb2Marshaller marshaller() {
        Jaxb2Marshaller marshaller = new Jaxb2Marshaller();
        marshaller.setContextPath("com.example.customer");
        return marshaller;
    }
    
    @Bean
    public CustomerClient customerClient(Jaxb2Marshaller marshaller) {
        CustomerClient client = new CustomerClient();
        client.setDefaultUri("http://localhost:8080/ws");
        client.setMarshaller(marshaller);
        client.setUnmarshaller(marshaller);
        return client;
    }
}

@Component
public class CustomerClient extends WebServiceGatewaySupport {
    
    public Customer getCustomer(Long customerId) {
        GetCustomerRequest request = new GetCustomerRequest();
        request.setCustomerId(customerId);
        
        GetCustomerResponse response = (GetCustomerResponse) 
            getWebServiceTemplate().marshalSendAndReceive(
                "http://localhost:8080/ws/customer", 
                request
            );
        
        return response.getCustomer();
    }
}

Best Practices

  1. Use Contract-First: Better for loose coupling and versioning
  2. Version Your Services: Include version in namespace
  3. Document Operations: Use clear operation names and descriptions
  4. Error Handling: Use SOAP faults for errors
  5. Security: Implement WS-Security for authentication
  6. Testing: Use SoapUI or Postman for testing
  7. Performance: Consider message size and compression
  8. Monitoring: Log requests and responses for debugging