Expand Authors Top

If you have a few years of experience in the Java ecosystem and you’d like to share that with the community, have a look at our Contribution Guidelines.

November Discount Launch 2022 – Top
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

November Discount Launch 2022 – TEMP TOP (NPI)
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Expanded Audience – Frontegg – Security (partner)
announcement - icon User management is very complex, when implemented properly. No surprise here.

Not having to roll all of that out manually, but instead integrating a mature, fully-fledged solution - yeah, that makes a lot of sense.
That's basically what Frontegg is - User Management for your application. It's focused on making your app scalable, secure and enjoyable for your users.
From signup to authentication, it supports simple scenarios all the way to complex and custom application logic.

Have a look:

>> Elegant User Management, Tailor-made for B2B SaaS

1. Overview

In this tutorial, we'll learn how to create a SOAP-based web service with Spring Boot Starter Web Services.

2. SOAP Web Services

In short, a web service is a machine-to-machine, platform independent service that allows communication over a network.

SOAP is a messaging protocol. Messages (requests and responses) are XML documents over HTTPThe XML contract is defined by the WSDL (Web Services Description Language). It provides a set of rules to define the messages, bindings, operations, and location of the service.

The XML used in SOAP can become extremely complex. For this reason, it's best to use SOAP with a framework, like JAX-WS or Spring, as we'll see in this tutorial.

3. Contract-First Development Style

There are two possible approaches when creating a web service: Contract-Last and Contract-First. When we use a contract-last approach, we start with the Java code, and generate the web service contract (WSDL) from the classes. When using contract-first, we start with the WSDL contract, from which we generate the Java classes.

Spring-WS only supports the contract-first development style.

4. Setting Up the Spring Boot Project

We'll create a Spring Boot project where we'll define our SOAP WS server.

4.1. Maven Dependencies

Let's start by adding the spring-boot-starter-parent to our project:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.7.2</version>
</parent>

Next, let's add the spring-boot-starter-web-services and wsdl4j dependencies:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web-services</artifactId>
</dependency>
<dependency>
    <groupId>wsdl4j</groupId>
    <artifactId>wsdl4j</artifactId>
</dependency>

4.2. The XSD File

The contract-first approach requires us to create the domain (methods and parameters) for our service first. We'll use an XML schema file (XSD) that Spring-WS will export automatically as a WSDL:

<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:tns="http://www.baeldung.com/springsoap/gen"
           targetNamespace="http://www.baeldung.com/springsoap/gen" elementFormDefault="qualified">

    <xs:element name="getCountryRequest">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="name" type="xs:string"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:element name="getCountryResponse">
        <xs:complexType>
            <xs:sequence>
                <xs:element name="country" type="tns:country"/>
            </xs:sequence>
        </xs:complexType>
    </xs:element>

    <xs:complexType name="country">
        <xs:sequence>
            <xs:element name="name" type="xs:string"/>
            <xs:element name="population" type="xs:int"/>
            <xs:element name="capital" type="xs:string"/>
            <xs:element name="currency" type="tns:currency"/>
        </xs:sequence>
    </xs:complexType>

    <xs:simpleType name="currency">
        <xs:restriction base="xs:string">
            <xs:enumeration value="GBP"/>
            <xs:enumeration value="EUR"/>
            <xs:enumeration value="PLN"/>
        </xs:restriction>
    </xs:simpleType>
</xs:schema>

In this file, we can see the format of the getCountryRequest web service request. We'll define it to accept one parameter of the type string.

Next, we'll define the format of the response, which contains an object of the type country.

Finally, we can see the currency object used within the country object.

4.3. Generate the Domain Java Classes

Now we'll generate the Java classes from the XSD file defined in the previous section. The jaxb2-maven-plugin will do this automatically during build time. The plugin uses the XJC tool as a code generation engine. XJC compiles the XSD schema file into fully annotated Java classes.

Let's add and configure the plugin in our pom.xml:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxb2-maven-plugin</artifactId>
    <version>1.6</version>
    <executions>
        <execution>
            <id>xjc</id>
            <goals>
                <goal>xjc</goal>
            </goals>
        </execution>
    </executions>
    <configuration>
        <schemaDirectory>${project.basedir}/src/main/resources/</schemaDirectory>
        <outputDirectory>${project.basedir}/src/main/java</outputDirectory>
        <clearOutputDir>false</clearOutputDir>
    </configuration>
</plugin>

Here we notice two important configurations:

  • <schemaDirectory>${project.basedir}/src/main/resources</schemaDirectory> – The location of the XSD file
  • <outputDirectory>${project.basedir}/src/main/java</outputDirectory> – Where we want our Java code to be generated to

To generate the Java classes, we could use the XJC tool from our Java installation. It's even more simple in our Maven project though, as the classes will be automatically generated during the usual Maven build:

mvn compile

4.4. Add the SOAP Web Service Endpoint

The SOAP web service endpoint class will handle all the incoming requests for the service. It'll initiate the processing, and send the response back.

Before defining this, we'll create a Country repository in order to provide data to the web service:

@Component
public class CountryRepository {

    private static final Map<String, Country> countries = new HashMap<>();

    @PostConstruct
    public void initData() {
        // initialize countries map
    }

    public Country findCountry(String name) {
        return countries.get(name);
    }
}

Next, we'll configure the endpoint:

@Endpoint
public class CountryEndpoint {

    private static final String NAMESPACE_URI = "http://www.baeldung.com/springsoap/gen";

    private CountryRepository countryRepository;

    @Autowired
    public CountryEndpoint(CountryRepository countryRepository) {
        this.countryRepository = countryRepository;
    }

    @PayloadRoot(namespace = NAMESPACE_URI, localPart = "getCountryRequest")
    @ResponsePayload
    public GetCountryResponse getCountry(@RequestPayload GetCountryRequest request) {
        GetCountryResponse response = new GetCountryResponse();
        response.setCountry(countryRepository.findCountry(request.getName()));

        return response;
    }
}

Here are a few details to notice:

  • @Endpoint – registers the class with Spring WS as a Web Service Endpoint
  • @PayloadRootdefines the handler method according to the namespace and localPart attributes
  • @ResponsePayload – indicates that this method returns a value to be mapped to the response payload
  • @RequestPayload – indicates that this method accepts a parameter to be mapped from the incoming request

4.5. The SOAP Web Service Configuration Beans

Now let's create a class for configuring the Spring message dispatcher servlet to receive the request:

@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter {
    // bean definitions
}

@EnableWs enables SOAP Web Service features in this Spring Boot application. The WebServiceConfig class extends the WsConfigurerAdapter base class, which configures the annotation-driven Spring-WS programming model.

Let's create a MessageDispatcherServlet, which is used for handling SOAP requests:

@Bean
public ServletRegistrationBean messageDispatcherServlet(ApplicationContext applicationContext) {
    MessageDispatcherServlet servlet = new MessageDispatcherServlet();
    servlet.setApplicationContext(applicationContext);
    servlet.setTransformWsdlLocations(true);
    return new ServletRegistrationBean(servlet, "/ws/*");
}

We'll set the injected ApplicationContext object of the servlet, so that Spring-WS can find other Spring beans.

We'll also enable the WSDL location servlet transformation. This transforms the location attribute of soap:address in the WSDL so that it reflects the URL of the incoming request.

Finally, we'll create a DefaultWsdl11Definition object. This exposes a standard WSDL 1.1 using an XsdSchema. The WSDL name will be the same as the bean name:

@Bean(name = "countries")
public DefaultWsdl11Definition defaultWsdl11Definition(XsdSchema countriesSchema) {
    DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
    wsdl11Definition.setPortTypeName("CountriesPort");
    wsdl11Definition.setLocationUri("/ws");
    wsdl11Definition.setTargetNamespace("http://www.baeldung.com/springsoap/gen");
    wsdl11Definition.setSchema(countriesSchema);
    return wsdl11Definition;
}

@Bean
public XsdSchema countriesSchema() {
    return new SimpleXsdSchema(new ClassPathResource("countries.xsd"));
}

5. Testing the SOAP Project

Once the project configuration has been completed, we're ready to test it.

5.1. Build and Run the Project

It's possible to create a WAR file and deploy it to an external application server. Instead, we'll use Spring Boot, which is a faster and easier way to get the application up and running.

First, we'll add the following class to make the application executable:

@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

Notice that we're not using any XML files (like web.xml) to create this application. It's all pure Java.

Now we're ready to build and run the application:

mvn spring-boot:run

To check if the application is running properly, we can open the WSDL through the URL: http://localhost:8080/ws/countries.wsdl

5.2. Test a SOAP Request

To test a request, we'll create the following file and name it request.xml:

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
                  xmlns:gs="http://www.baeldung.com/springsoap/gen">
    <soapenv:Header/>
    <soapenv:Body>
        <gs:getCountryRequest>
            <gs:name>Spain</gs:name>
        </gs:getCountryRequest>
    </soapenv:Body>
</soapenv:Envelope>

To send the request to our test server, we can use external tools, like SoapUI or the Google Chrome extension Wizdler. Another way is to run the following command in our shell:

curl --header "content-type: text/xml" -d @request.xml http://localhost:8080/ws

The resulting response might not be easy to read without indentation or line breaks.

To see it formatted, we can copy paste it to our IDE or another tool. If we've installed xmllib2, we can pipe the output of our curl command to xmllint:

curl [command-line-options] | xmllint --format -

The response should contain information about Spain:

<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>
<SOAP-ENV:Body>
    <ns2:getCountryResponse xmlns:ns2="http://www.baeldung.com/springsoap/gen">
        <ns2:country>
            <ns2:name>Spain</ns2:name>
            <ns2:population>46704314</ns2:population>
            <ns2:capital>Madrid</ns2:capital>
            <ns2:currency>EUR</ns2:currency>
        </ns2:country>
    </ns2:getCountryResponse>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>

6. Conclusion

In this article, we learned how to create a SOAP web service using Spring Boot. We also demonstrated how to generate Java code from an XSD file. Finally, we configured the Spring beans needed to process the SOAP requests.

The complete source code is available over on GitHub.

November Discount Launch 2022 – Bottom
We’re finally running a Black Friday launch. All Courses are 30% off until next Friday:

>> GET ACCESS NOW

Generic footer banner
Comments are closed on this article!