Build, Test, and Containerize a JakartaEE REST API With Open Liberty and Podman

This is a complete, beginner-friendly, end-to-end guide for building, containerizing, and testing a Java 21 REST API with Open Liberty and Podman, with clear descriptions and step-by-step IntelliJ IDEA instructions.

1. Prerequisites and Setup

Purpose:
Prepare your development environment with all necessary tools to build, containerize, and run your Java 21 REST API with Open Liberty and Podman.

A. Install Java 21

  • Download and install Java 21 JDK (e.g., from Adoptium).
  • Set JAVA_HOME to your Java 21 installation.
  • On Windows, add JAVA_HOME/bin to your PATH.

B. Install Maven

  • Download and install Maven 3.8+ (official site).
  • Verify installation:

And you should see something similar to the below:

Maven mvn -v

C. Install Podman or Podman Desktop

  • Download Podman Desktop for Windows/macOS or install Podman CLI for Linux.
  • On Windows/macOS, initialize the Podman machine:

Verify Podman works:

D. Install IntelliJ IDEA

2. Project Structure

Purpose:
Organize your project into a clear multi-module Maven layout, separating the REST application and integration tests for modular builds and containerization.

3. Creating the Project in IntelliJ IDEA

Purpose:
Set up your Maven multi-module project using IntelliJ IDEA’s tools for easy project management.

A. Create Parent Project

  1. Open IntelliJ IDEA.
  2. Click New Project.
  3. Select Maven as the project type.
  4. Set the GroupId (e.g., com.example) and ArtifactId (e.g., parent).
  5. Choose Java 21 as the JDK (see below if not listed).
  6. Click Create.

B. Add Java 21 JDK to IntelliJ

  • Go to File → Project Structure → Project.
  • Under Project SDK, click Add JDK and select your Java 21 install folder.
  • Set Project language level to 21 (Preview) if you want Java 21 features.

C. Add Modules

  1. Right-click the parent project → New → Module → Maven.
  2. Name the first module restful-war (packaging: war).
  3. Repeat for integration-tests (packaging: jar).

4. Parent POM: Java 21 Compilation

Purpose:
Ensure all modules compile to Java 21 bytecode, preventing runtime compatibility issues.

root/pom.xml

Tip:
This ensures Java 21 compatibility even if your system JDK is newer.

5. RESTful Application Code

Purpose:
Define your REST application, path and endpoint.

restful-war/src/main/java/com/example/RestApplication.java

restful-war/src/main/java/com/example/HelloResource.java

6. Open Liberty Configuration

Purpose:
The server.xml configures the Open Liberty application server, in this case for the Jakarta EE features, HTTP ports, context root, and logging.

restful-war/src/main/liberty/config/server.xml

Tips:

  • The API will be at /restful/api/hello.
  • Logs will be visible via podman logs.

7. WAR Module POM

Purpose:
The war module will build your web application resource (WAR) file. This POM declares the dependencies and packaging for your REST API WAR module.

restful-war/pom.xml

8. Integration Tests Module: Copy WAR and Config

Purpose:
The integration test module is responsible for integration testing your endpoint. This will copy the compiled WAR and Liberty server configuration o the integration test module, run the config to setup your Podman container image and deploy your war to it, and then run an integration test against the application running in the container to confirm it works as expected.

The section of the pom below uses the maven-dependency-plugin to copy the war file to this module, and then the maven-resources-plugin to copy the open liberty configuration, (in this case just the server.xml) to this module.

integration-tests/pom.xml 

9. Containerfile for Liberty Java 21

Purpose:
Rather than having a local install of open liberty, deploying the war and then running it, we are going to define the podman container image build instructions for Open Liberty running Java 21 and your application. We will use maven to run the build of the image

integration-tests/Containerfile

10. Podman Maven Plugin for Image Build

Purpose:
Automate Podman container image building within Maven using the Podman Maven plugin.

integration-tests/pom.xml (snippet)

Tip:
Use a local image name like integration-tests to avoid Podman registry errors.

11. Exec Maven Plugin: Container Lifecycle

Purpose:
Control container lifecycle during integration tests by stopping/removing old containers and running new ones, all triggered automatically in the Maven build phases.

integration-tests/pom.xml (snippet)

Tip:
Use multiple <execution> blocks in a single plugin declaration for correct ordering.

12. JUnit Integration Test

Purpose:
This will verify your REST API endpoint is accessible and return the expected response by running the HTTP test against the containerized application.

integration-tests/src/test/java/com/example/HelloIT.java

Tip:
Update the URL to match your context root (server.xml) , @ApplicationPath (RestApplication.java) and @Path (HelloResource.java).

Add the maven failsafe plugin to ensure your integrations tests are run as part of the mvn clean install build of the parent.

13. Running and Testing in IntelliJ IDEA

Purpose:
Build, run, and test your project easily from IntelliJ IDEA.

A. Build the Project

  • Right-click the parent project → Maven → Reload Project.
  • Open a terminal (bottom panel) and run:
  • Or use the Maven panel to run Lifecycle → clean and install.

This is what you would expect to see if all was successful

B. Run Integration Tests

  • Right-click the integration-tests module → Run ‘All Tests’.
  • Or run:
  • Check the Run or Test Results window for test output.

C. Debugging and Logs

  • Use the Terminal in IntelliJ to run Podman commands (see below).
  • View container logs:

D. HTTP Client in IntelliJ

  • You can use IntelliJ’s built-in HTTP client (create a .http file) to manually test endpoints:

14. Useful Podman Commands

Purpose:
Provide handy Podman commands for manual container and image management during development and troubleshooting.

StepCommand/Action
Build all modulesmvn clean install
Build integration imagemvn podman:build -pl integration-tests
Run integration testsmvn verify -pl integration-tests
Manually run containerpodman run --name liberty-test -p 9080:9080 integration-tests:latest
Stop containerpodman stop liberty-test
Remove containerpodman rm liberty-test
View logspodman logs liberty-test
Exec into containerpodman exec -it liberty-test sh

15. Podman Image Management

Purpose:
Keep your Podman environment clean by pruning unused images and checking image build timestamps to avoid stale deployments.

  • Prune unused images (careful: this deletes all unreferenced images!):

Check image age:

Check running containers:

16. Troubleshooting & Tips

Purpose:
Summarize common issues and best practices.

  • 404 errors:
    Double-check your context root, @ApplicationPath, and test URLs.
  • Class version errors:
    Ensure Maven is compiling with <release>21</release> and your image uses Java 21.
  • Image not updating:
    Use podman build --no-cache ... and confirm with podman history.
  • Podman registry errors:
    Use local image names (not org.example/...) to avoid Podman trying to pull from a non-existent registry.
  • Order of plugin execution:
    List plugins in <plugins> in the order you want them to run for the same phase.
  • Multiple executions:
    Use multiple <execution> blocks inside a single plugin declaration, not multiple plugin declarations.

17. References

Purpose:
Official documentation and guides for further reading.

Leave a Comment