mvn -v
Building a web application with Maven
Prerequisites:
Learn how to build and test a simple web application using Maven and Open Liberty.
What you’ll learn
You will learn how to configure a simple web servlet application using Maven and the Liberty Maven plugin. When you compile and build the application code, Maven downloads and installs Open Liberty. If you run the application, Maven creates an Open Liberty instance and runs the application on it. The application displays a simple web page with a link that, when clicked, calls the servlet to return a simple response of Hello! How are you today?
.
One benefit of using a build tool like Maven is that you can define the details of the project and any dependencies it has, and Maven automatically downloads and installs the dependencies. Another benefit of using Maven is that it can run repeatable, automated tests on the application. You can, of course, test your application manually by starting a Liberty instance and pointing a web browser at the application URL. However, automated tests are a much better approach because you can easily rerun the same tests each time the application is built. If the tests don’t pass after you change the application, the build fails, and you know that you introduced a regression that requires a fix to your code.
Choosing a build tool often comes down to personal or organizational preference, but you might choose to use Maven for several reasons. Maven defines its builds by using XML, which is probably familiar to you already. As a mature, commonly used build tool, Maven probably integrates with whichever IDE you prefer to use. Maven also has an extensive plug-in library that offers various ways to quickly customize your build. Maven can be a good choice if your team is already familiar with it.
You will create a Maven build definition file that’s called a pom.xml
file, which stands for Project Object Model, and use it to build your web application. You will then create a simple, automated test and configure Maven to automatically run the test.
Installing Maven
If Maven isn’t already installed, download the binary zip or tar.gz file. Then, follow the installation instructions for your operating system to extract the .zip
file and add the bin
directory, which contains the mvn
command to the PATH
on your computer.
Run the following command to test that Maven is installed:
If Maven is installed properly, you see information about the Maven installation similar to the following example:
Apache Maven 3.8.1 (05c21c65bdfed0f71a2f2ada8b84da59348c4c5d)
Maven home: /Applications/Maven/apache-maven-3.8.1
Java version: 11.0.12, vendor: International Business Machines Corporation, runtime: /Library/Java/JavaVirtualMachines/ibm-semeru-open-11.jdk/Contents/Home
Default locale: en_US, platform encoding: UTF-8
OS name: "mac os x", version: "11.6", arch: "x86_64", family: "mac"
Getting started
The fastest way to work through this guide is to clone the Git repository and use the projects that are provided inside:
git clone https://github.com/openliberty/guide-maven-intro.git
cd guide-maven-intro
The start
directory contains the starting project that you will build upon.
The finish
directory contains the finished project that you will build.
Before you begin, make sure you have all the necessary prerequisites.
Try what you’ll build
The finish
directory in the root of this guide contains the finished application. Give it a try before you proceed.
To try out the application, first go to the finish
directory and run Maven with the liberty:run
goal to build the application and deploy it to Open Liberty:
cd finish
mvn liberty:run
After you see the following message, your Liberty instance is ready.
The guideServer server is ready to run a smarter planet.
Navigate your browser to the http://localhost:9080/ServletSample/servlet URL to access the application. The servlet returns a simple response of Hello! How are you today?
.
After you are finished checking out the application, stop the Liberty instance by pressing CTRL+C
in the command-line session where you ran Liberty. Alternatively, you can run the liberty:stop
goal from the finish
directory in another shell session:
mvn liberty:stop
Creating a simple application
The simple web application that you will build using Maven and Open Liberty is provided for you in the start
directory so that you can focus on learning about Maven. This application uses a standard Maven directory structure, eliminating the need to customize the pom.xml
file so that Maven understands your project layout.
All the application source code, including the Open Liberty server.xml
configuration file, is in the src/main/liberty/config
directory:
└── src
└── main
└── java
└── resources
└── webapp
└── liberty
└── config
Creating the project POM file
Navigate to the start
directory to begin.
Before you can build the project, define the Maven Project Object Model (POM) file, the pom.xml
.
Create the pom.xml file in thestart
directory.pom.xml
pom.xml
1<?xml version='1.0' encoding='utf-8'?>
2<!-- tag::project[] -->
3<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4<!-- end::project[] -->
5 <!-- tag::modelVersion[] -->
6 <modelVersion>4.0.0</modelVersion>
7 <!-- end::modelVersion[] -->
8
9 <groupId>io.openliberty.guides</groupId>
10 <!-- tag::artifactID[] -->
11 <artifactId>ServletSample</artifactId>
12 <!-- end::artifactID[] -->
13 <!-- tag::packaging[] -->
14 <packaging>war</packaging>
15 <!-- end::packaging[] -->
16 <version>1.0-SNAPSHOT</version>
17
18 <!-- tag::properties[] -->
19 <properties>
20 <!-- tag::encoding[] -->
21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
23 <!-- end::encoding[] -->
24 <!-- tag::java-version[] -->
25 <maven.compiler.source>11</maven.compiler.source>
26 <maven.compiler.target>11</maven.compiler.target>
27 <!-- end::java-version[] -->
28 <!-- Liberty configuration -->
29 <!-- tag::http.port[] -->
30 <liberty.var.http.port>9080</liberty.var.http.port>
31 <!-- end::http.port[] -->
32 <liberty.var.https.port>9443</liberty.var.https.port>
33 <liberty.var.app.context.root>${project.artifactId}</liberty.var.app.context.root>
34 </properties>
35 <!-- end::properties[] -->
36
37 <!-- tag::dependencies[] -->
38 <dependencies>
39 <!-- Provided dependencies -->
40 <!-- tag::jakarta.jakartaee-api[] -->
41 <dependency>
42 <!-- tag::groupID-api[] -->
43 <groupId>jakarta.platform</groupId>
44 <!-- end::groupID-api[] -->
45 <!-- tag::artifactID-api[] -->
46 <artifactId>jakarta.jakartaee-api</artifactId>
47 <!-- end::artifactID-api[] -->
48 <!-- tag::version-api[] -->
49 <version>10.0.0</version>
50 <!-- end::version-api[] -->
51 <!-- tag::scope-api[] -->
52 <scope>provided</scope>
53 <!-- end::scope-api[] -->
54 </dependency>
55 <!-- end::jakarta.jakartaee-api[] -->
56 <dependency>
57 <groupId>org.eclipse.microprofile</groupId>
58 <artifactId>microprofile</artifactId>
59 <version>6.1</version>
60 <type>pom</type>
61 <scope>provided</scope>
62 </dependency>
63 <!-- For testing -->
64 <!-- tag::commons-httpclient[] -->
65 <dependency>
66 <groupId>org.apache.httpcomponents</groupId>
67 <artifactId>httpclient</artifactId>
68 <version>4.5.14</version>
69 <!-- tag::test1[] -->
70 <scope>test</scope>
71 <!-- end::test1[] -->
72 </dependency>
73 <!-- end::commons-httpclient[] -->
74 <!-- tag::junit[] -->
75 <dependency>
76 <groupId>org.junit.jupiter</groupId>
77 <artifactId>junit-jupiter</artifactId>
78 <version>5.11.3</version>
79 <!-- tag::test2[] -->
80 <scope>test</scope>
81 <!-- end::test2[] -->
82 </dependency>
83 <!-- end::junit[] -->
84 </dependencies>
85 <!-- end::dependencies[] -->
86
87 <!-- tag::build[] -->
88 <build>
89 <finalName>${project.artifactId}</finalName>
90 <plugins>
91 <plugin>
92 <groupId>org.apache.maven.plugins</groupId>
93 <artifactId>maven-war-plugin</artifactId>
94 <version>3.4.0</version>
95 </plugin>
96 <!-- tag::liberty-maven-plugin[] -->
97 <plugin>
98 <groupId>io.openliberty.tools</groupId>
99 <artifactId>liberty-maven-plugin</artifactId>
100 <version>3.11.1</version>
101 <!-- tag::configuration[] -->
102 <configuration>
103 <!-- tag::serverName[] -->
104 <serverName>guideServer</serverName>
105 <!-- end::serverName[] -->
106 </configuration>
107 <!-- end::configuration[] -->
108 </plugin>
109 <!-- end::liberty-maven-plugin[] -->
110 <!-- tag::maven-failsafe-plugin[] -->
111 <plugin>
112 <groupId>org.apache.maven.plugins</groupId>
113 <artifactId>maven-failsafe-plugin</artifactId>
114 <version>3.5.1</version>
115 <configuration>
116 <!-- tag::system-property-variables[] -->
117 <systemPropertyVariables>
118 <!-- tag::http-port[] -->
119 <http.port>${liberty.var.http.port}</http.port>
120 <!-- end::http-port[] -->
121 <!-- tag::war-name[] -->
122 <war.name>${liberty.var.app.context.root}</war.name>
123 <!-- end::war-name[] -->
124 </systemPropertyVariables>
125 <!-- end::system-property-variables[] -->
126 </configuration>
127 </plugin>
128 <!-- end::maven-failsafe-plugin[] -->
129 </plugins>
130 </build>
131 <!-- end::build[] -->
132</project>
The pom.xml
file starts with a root project
element and a modelversion
element, which is always set to 4.0.0
.
A typical POM for a Liberty application contains the following sections:
-
Project coordinates: The identifiers for this application.
-
Properties (
properties
): Any properties for the project go here, including compilation details and any values that are referenced during compilation of the Java source code and generating the application. -
Dependencies (
dependencies
): Any Java dependencies that are required for compiling, testing, and running the application are listed here. -
Build plugins (
build
): Maven is modular and each of its capabilities is provided by a separate plugin. This is where you specify which Maven plugins should be used to build this project and any configuration information needed by those plugins.
The project coordinates describe the name and version of the application. The artifactId
gives a name to the web application project, which is used to name the output files that are generated by the build (e.g. the WAR file) and the Open Liberty instance that is created. You’ll notice that other fields in the pom.xml
file use variables that are resolved by the artifactId
field. This is so that you can update the name of the sample application, including files generated by Maven, in a single place in the pom.xml
file. The value of the packaging
field is war
so that the project output artifact is a WAR file.
The first four properties in the properties section of the project, just define the encoding (UTF-8
) and version of Java (Java 11
) that Maven uses to compile the application source code.
Open Liberty configuration properties provide you with a single place to specify values that are used in multiple places throughout the application. For example, the http.port
value is used in both the Liberty server.xml
configuration file and will be used in the test class that you will add (EndpointIT.java
) to the application. Because the http.port
value is specified in the pom.xml
file, you can easily change the port number that the Liberty instance runs on without updating the application code in multiple places.
HelloServlet.java
The HelloServlet.java
class depends on jakarta.jakartaee-api
to compile. Maven will download this dependency from the Maven Central repository using the groupId
, artifactId
, and version
details that you provide here. The dependency is set to provided
, which means that the API is in the Liberty runtime and doesn’t need to be packaged by the application.
The build
section gives details of the two plugins that Maven uses to build this project.
-
The Maven plugin for generating a WAR file as one of the output files.
-
The Liberty Maven plug-in, which allows you to install applications into Open Liberty and manage the associated Liberty instances.
In the liberty-maven-plugin
plug-in section, you can add a configuration
element to specify Open Liberty configuration details. For example, the serverName
field defines the name of the Open Liberty instance that Maven creates. You specified guideServer
as the value for serverName
. If the serverName
field is not included, the default value is defaultServer
.
server.xml
Running the application
When you run Open Liberty in dev mode, dev mode listens for file changes and automatically recompiles and deploys your updates whenever you save a new change. Run the following goal to start Open Liberty in dev mode:
mvn liberty:dev
After you see the following message, your Liberty instance is ready in dev mode:
************************************************************** * Liberty is running in dev mode.
Dev mode holds your command-line session to listen for file changes. Open another command-line session to continue, or open the project in your editor.
Navigate your browser to the http://localhost:9080/ServletSample/servlet URL to access the application. The servlet returns a simple response of Hello! How are you today?
.
Testing the web application
One of the benefits of building an application with Maven is that Maven can be configured to run a set of tests. You can write tests for the individual units of code outside of a running Liberty instance (unit tests), or you can write them to call the Liberty instance directly (integration tests). In this example you will create a simple integration test that checks that the web page opens and that the correct response is returned when the link is clicked.
Create theEndpointIT
class.src/test/java/io/openliberty/guides/hello/it/EndpointIT.java
EndpointIT.java
The test class name ends in IT
to indicate that it contains an integration test.
Maven is configured to run the integration test using the maven-failsafe-plugin
. The systemPropertyVariables
section defines some variables that the test class uses. The test code needs to know where to find the application that it is testing. While the port number and context root information can be hardcoded in the test class, it is better to specify it in a single place like the Maven pom.xml
file because this information is also used by other files in the project. The systemPropertyVariables
section passes these details to the Java test program as a series of system properties, resolving the http.port
and war.name
variables.
pom.xml
1<?xml version='1.0' encoding='utf-8'?>
2<!-- tag::project[] -->
3<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4<!-- end::project[] -->
5 <!-- tag::modelVersion[] -->
6 <modelVersion>4.0.0</modelVersion>
7 <!-- end::modelVersion[] -->
8
9 <groupId>io.openliberty.guides</groupId>
10 <!-- tag::artifactID[] -->
11 <artifactId>ServletSample</artifactId>
12 <!-- end::artifactID[] -->
13 <!-- tag::packaging[] -->
14 <packaging>war</packaging>
15 <!-- end::packaging[] -->
16 <version>1.0-SNAPSHOT</version>
17
18 <!-- tag::properties[] -->
19 <properties>
20 <!-- tag::encoding[] -->
21 <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
22 <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
23 <!-- end::encoding[] -->
24 <!-- tag::java-version[] -->
25 <maven.compiler.source>11</maven.compiler.source>
26 <maven.compiler.target>11</maven.compiler.target>
27 <!-- end::java-version[] -->
28 <!-- Liberty configuration -->
29 <!-- tag::http.port[] -->
30 <liberty.var.http.port>9080</liberty.var.http.port>
31 <!-- end::http.port[] -->
32 <liberty.var.https.port>9443</liberty.var.https.port>
33 <liberty.var.app.context.root>${project.artifactId}</liberty.var.app.context.root>
34 </properties>
35 <!-- end::properties[] -->
36
37 <!-- tag::dependencies[] -->
38 <dependencies>
39 <!-- Provided dependencies -->
40 <!-- tag::jakarta.jakartaee-api[] -->
41 <dependency>
42 <!-- tag::groupID-api[] -->
43 <groupId>jakarta.platform</groupId>
44 <!-- end::groupID-api[] -->
45 <!-- tag::artifactID-api[] -->
46 <artifactId>jakarta.jakartaee-api</artifactId>
47 <!-- end::artifactID-api[] -->
48 <!-- tag::version-api[] -->
49 <version>10.0.0</version>
50 <!-- end::version-api[] -->
51 <!-- tag::scope-api[] -->
52 <scope>provided</scope>
53 <!-- end::scope-api[] -->
54 </dependency>
55 <!-- end::jakarta.jakartaee-api[] -->
56 <dependency>
57 <groupId>org.eclipse.microprofile</groupId>
58 <artifactId>microprofile</artifactId>
59 <version>6.1</version>
60 <type>pom</type>
61 <scope>provided</scope>
62 </dependency>
63 <!-- For testing -->
64 <!-- tag::commons-httpclient[] -->
65 <dependency>
66 <groupId>org.apache.httpcomponents</groupId>
67 <artifactId>httpclient</artifactId>
68 <version>4.5.14</version>
69 <!-- tag::test1[] -->
70 <scope>test</scope>
71 <!-- end::test1[] -->
72 </dependency>
73 <!-- end::commons-httpclient[] -->
74 <!-- tag::junit[] -->
75 <dependency>
76 <groupId>org.junit.jupiter</groupId>
77 <artifactId>junit-jupiter</artifactId>
78 <version>5.11.3</version>
79 <!-- tag::test2[] -->
80 <scope>test</scope>
81 <!-- end::test2[] -->
82 </dependency>
83 <!-- end::junit[] -->
84 </dependencies>
85 <!-- end::dependencies[] -->
86
87 <!-- tag::build[] -->
88 <build>
89 <finalName>${project.artifactId}</finalName>
90 <plugins>
91 <plugin>
92 <groupId>org.apache.maven.plugins</groupId>
93 <artifactId>maven-war-plugin</artifactId>
94 <version>3.4.0</version>
95 </plugin>
96 <!-- tag::liberty-maven-plugin[] -->
97 <plugin>
98 <groupId>io.openliberty.tools</groupId>
99 <artifactId>liberty-maven-plugin</artifactId>
100 <version>3.11.1</version>
101 <!-- tag::configuration[] -->
102 <configuration>
103 <!-- tag::serverName[] -->
104 <serverName>guideServer</serverName>
105 <!-- end::serverName[] -->
106 </configuration>
107 <!-- end::configuration[] -->
108 </plugin>
109 <!-- end::liberty-maven-plugin[] -->
110 <!-- tag::maven-failsafe-plugin[] -->
111 <plugin>
112 <groupId>org.apache.maven.plugins</groupId>
113 <artifactId>maven-failsafe-plugin</artifactId>
114 <version>3.5.1</version>
115 <configuration>
116 <!-- tag::system-property-variables[] -->
117 <systemPropertyVariables>
118 <!-- tag::http-port[] -->
119 <http.port>${liberty.var.http.port}</http.port>
120 <!-- end::http-port[] -->
121 <!-- tag::war-name[] -->
122 <war.name>${liberty.var.app.context.root}</war.name>
123 <!-- end::war-name[] -->
124 </systemPropertyVariables>
125 <!-- end::system-property-variables[] -->
126 </configuration>
127 </plugin>
128 <!-- end::maven-failsafe-plugin[] -->
129 </plugins>
130 </build>
131 <!-- end::build[] -->
132</project>
The following lines in the EndpointIT
test class uses these system variables to build up the URL of the application.
In the test class, after defining how to build the application URL, the @Test
annotation indicates the start of the test method.
In the try block
of the test method, an HTTP GET
request to the URL of the application returns a status code. If the response to the request includes the string Hello! How are you today?
, the test passes. If that string is not in the response, the test fails. The HTTP client then disconnects from the application.
In the import
statements of this test class, you’ll notice that the test has some new dependencies. Before the test can be compiled by Maven, you need to update the pom.xml
to include these dependencies.
The Apache httpclient
and junit-jupiter-engine
dependencies are needed to compile and run the integration test EndpointIT
class. The scope for each of the dependencies is set to test
because the libraries are needed only during the Maven build and do not needed to be packaged with the application.
Now, the created WAR file contains the web application, and dev mode can run any integration test classes that it finds. Integration test classes are classes with names that end in IT
.
The directory structure of the project should now look like this:
└── src
├── main
│ └── java
│ └── resources
│ └── webapp
│ └── liberty
│ └── config
└── test
└── java
Running the tests
Because you started Open Liberty in dev mode, you can run the tests by pressing the enter/return
key from the command-line session where you started dev mode.
You see the following output:
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running io.openliberty.guides.hello.it.EndpointIT
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.255 sec - in io.openliberty.guides.hello.it.EndpointIT
Results :
Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
To see whether the test detects a failure, change the response string
in the servlet src/main/java/io/openliberty/guides/hello/HelloServlet.java
so that it doesn’t match the string that the test is looking for. Then re-run the tests and check that the test fails.
HelloServlet.java
When you are done checking out the service, exit dev mode by pressing CTRL+C
in the command-line session where you ran Liberty.
Great work! You’re done!
You built and tested a web application project with an Open Liberty instance using Maven.
Guide Attribution
Building a web application with Maven by Open Liberty is licensed under CC BY-ND 4.0
Prerequisites:
Nice work! Where to next?
What did you think of this guide?
Thank you for your feedback!
What could make this guide better?
Raise an issue to share feedback
Create a pull request to contribute to this guide
Need help?
Ask a question on Stack Overflow