Simplifying IBM WebSphere Migration with Spring Cloud Contract

May 15, 2025 

Migrating enterprise applications is rarely straightforward – especially when faced with limited test coverage, tight deadlines, and constrained resources. Even if the task seems simple on paper, like porting existing functionality from one platform to another, real-world conditions tend to complicate things. That was precisely the case for our team when we migrated a monolithic enterprise system to the Azure cloud environment.

In this article, we examine how the IBA Group project used Spring Cloud Contract to speed up integration testing, maintain service integrity, and keep systems working reliably during complex migrations, including those from platforms like IBM WebSphere. We also introduce lesser-known but powerful features that make this tool invaluable during code transitions.

 

Table of Content

What Is Spring Cloud Contract?

Spring Cloud Contract is an umbrella project holding solutions that help users in successfully implementing the Consumer Driven Contracts approach. Currently, Spring Cloud Contract consists of Spring Cloud Contract Verifier, a tool that enables Consumer Driven Contract (CDC) development of JVM-based applications. It makes sure that services can communicate without integration issues by defining a contract between them.

Why have we chosen Spring Cloud Contract?

We were tasked with migrating a medium-sized, IBM WebSphere-deployed monolithic enterprise application to the Azure cloud. The migration process involved several stages, one of which was the migration of the Client-Server web application. The UI part, built with React.js, required only minor changes. The team decided to move the Java component’s functionality to the Spring Reactor project. Ultimately, the Java part would become a separate REST API microservice, a resource service protected by Okta.

During the project analysis, we made an unpleasant discovery – the absence of tests. The team needed to find a way to quickly and efficiently implement testing. It was crucial for verifying that everything worked properly and without any issues.

Spring Contracts provided the ability to create integration tests from captured responses, which turned out to be a very useful feature, particularly given the task we had and the time we had spent. 

Let’s explore how we’ve adopted this approach and quickly enabled integration tests for token-protected Spring Reactor microservices.

How to enable Spring Contracts

We created a pet project spring_contract_example to demonstrate the required settings and code examples.

Understanding the Project Structure

Project structure

  • /src/main/java: the source code for the example application
  • /src/test/java: contains tests, including Spring contract base tests
  • /src/test/resources/contracts/: contains contract definitions written in Groovy and captured responses in JSON format
  • /target/generated-test-sources/contracts: auto-generated tests based on the contract files

1. Maven settings

First, add the required Spring Contracts libraries under the dependencies section of your pom.xml file:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-verifier</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
    <version>${spring-cloud-contract.version}</version>
    <scope>test</scope>
</dependency>

Under the plugins section, add the Spring Contracts maven plugin:

    <!–  Spring Cloud Contract Verifier Maven plugin: –>
    <plugin>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-contract-maven-plugin</artifactId>
        <version>${spring-cloud-contract.version}</version>
        <extensions>true</extensions>
        <configuration>
            <packageWithBaseClasses>eu.ibagroup.am.springcontracts.contracts</packageWithBaseClasses>
            <testMode>EXPLICIT</testMode>
        </configuration>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>pushStubsToScm</goal>
                </goals>
            </execution>
        </executions>
    </plugin>

The key settings here are:

  • testMode attribute value should be EXPLICIT. Those are the required settings for Spring Reactor projects.
  • packageWithBaseClasses should point to the base tests parent folder inside your /src/test/java folder.

Finally, add Groovy language support:

<plugin>
    <groupId>org.codehaus.gmavenplus</groupId>
    <artifactId>gmavenplus-plugin</artifactId>
    <version>1.13.1</version>
    <executions>
        <execution>
            <goals>
                <goal>addSources</goal>
                <goal>addTestSources</goal>
                <goal>generateStubs</goal>
                <goal>compile</goal>
                <goal>generateTestStubs</goal>
                <goal>compileTests</goal>
                <goal>removeStubs</goal>
                <goal>removeTestStubs</goal>
            </goals>
        </execution>
    </executions>
</plugin>

… and declare auto-generated tests as additional project source folder:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>build-helper-maven-plugin</artifactId>
    <executions>
        <execution>
            <id>add-test-source</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>add-test-source</goal>
            </goals>
            <configuration>
                <sources>
                    <directory>
                        ${project.build.directory}/generated-test-sources/contracts</directory>
                </sources>
            </configuration>
        </execution>
    </executions>
</plugin>

 

2. Creating contract files

The contract file is self-descriptive. The definition begins with the Contract.make method, where you can declare the expected request and response, provide the required authorization headers, and define additional validation for the output.

package contracts
import org.springframework.cloud.contract.spec.Contract
Contract.make {
     description(‘Should return user contracts list’)
     name(‘user-contract-list-possitive’)
     request {
          method(‘GET’)
          urlPath($(consumer(‘/api/contracts’), producer(‘/contracts’)))
          headers {
                header(authorization(), “Bearer admin”)
          }
     }
     response {
          status(200)
          headers {
            contentType(‘application/json’)
          }
          body(file(‘example-list.json’))
          bodyMatchers {
                  jsonPath(‘$’, byType {
                        minOccurrence(1)
                    })
                    jsonPath(‘$[*].id’, byRegex(‘[0-9]+’).asString())
                    jsonPath(‘$[*].contractNumber’, byRegex(‘[a-zA-Z]+’).asString())
                    jsonPath(‘$[*].country’, byRegex(‘[a-zA-Z]{2}’).asString())
          }
    }
}

package contracts

 

This contract example specifies that when a GET request is made to /api/user with Bearer authorization header having value admin, the server should respond with a 200 status code and a JSON body from the example-list.json file.

The content of this file was captured from the original application. That is the key point in validating compatibility between the original and migrated applications.

Moreover, in the body matchers section, we can apply additional validation to the expected output. In our case, it confirms that the response body contains an array with at least one item and that the attributes of the items match the corresponding regular expressions.

Supercharge Your IBM WebSphere Migration with AI

3. Implementing contract base tests

Contract-based test classes play a crucial role in the testing cycle. Each auto-generated test extends the base test class. At this point, developers should configure tests for execution and manage additional test resources, e.g., test containers.

Let’s take a look at the base test class:

@TestInstance(Lifecycle.PER_CLASS)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = “server.port=0”)
public class PositiveBase extends SpringContractsBase{
    @Value(“${local.server.port:8080}”)
    private int port;
 
    @BeforeAll
    public void init() {
        mockDecoder();
        initRestAssured(port);
    }
}
 

As we defined the Spring Contract plugin testMode attribute as EXPLICIT, the Rest Assured client will be used as a test client in this case.


To run a black-box like application container:

  • Run application on random port webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, properties = “server.port=0”
  • Capture randomly generated port value in local variable
  • Configure Rest Assured client to use that port number like RestAssured.baseURI = “http://localhost:” + port;.


The final issue to address before we can run our tests is providing a valid token as part of the API call. This will be challenging for us to obtain.

When a request is made with a token, the application delegates the task to ReactiveJwtDecoder to decode and validate the token. It then returns the parsed object or raises an exception if something goes wrong.

One of the easiest ways to address this issue would be to mock the ReactiveJwtDecoder.decode method:

public abstract class SpringContractsBase {
 
    private final String corporateEmailPostfix = “@company.com”;
 
    @MockBean
    ReactiveJwtDecoder jwtDecoder;
 
    protected void mockDecoder() {
        when(jwtDecoder.decode(any())).then(answer -> {
            Map<String, Object> claims = new HashMap<>();
            String userId = Optional.of(answer.getArgument(0, String.class)).orElse(“”);
            if (!userId.endsWith(corporateEmailPostfix)) {
                userId += corporateEmailPostfix;
            }
            claims.putAll(Collections.singletonMap(“email”, userId));
            Jwt jwt = new Jwt(“token”,
                Instant.now(),
                Instant.now().plusSeconds(60),
                Collections.singletonMap(“key”, “value”),
                claims
            );
            return Mono.just(jwt);
        });
    }

Here, we’re simply creating a user ID that will be recognized by the application. This is done by concatenating the received authorization token value with static text.

 

4. Generating and Running Tests

Run the following command to generate tests from the contract files:

mvn clean install

The plugin will generate test classes in the ${project.build.directory}/generated-test-sources/ These tests verify that the service adheres to the defined contract.

To execute the tests run:

mvn test    

Conclusion

Spring Cloud Contract is a powerful tool that allows teams to detect and fix integration issues early in the development cycle, reduces integration testing overhead, and may even serve as an alternative for documentation.

In this article, we showed how to quickly and with reasonable effort build integration tests to check compatibility between the original and migrated applications.

In the next part of this series, we will demonstrate how to improve team collaboration using Spring Cloud Contract.

Need Support with IBM WebSphere Migration?

If you’re planning to migrate from IBM WebSphere or modernize your current application landscape, having the right expertise can make a significant difference. At IBA Group, we’ve guided enterprises through complex transformations using proven frameworks like Spring Cloud Contract.

Whether you’re just starting or already working through integration challenges, we’re here to support your goals with hands-on experience and practical solutions.

Reach out to us to learn how we can help accelerate your migration journey.