We will now move away from basic features of Java towards higher level tools for implementing and
maintaining Java programs. We will start by considering a tool for managing the build process and
external library dependencies of a Java project. There are several such tools. We have chosen to
focus on a tool called Maven, which is probably the most popular Java project build management
tool. Maven allows us to e.g. define how thee project should be compiled and what kind of external
libraries it needs. Another especially recently quite popular such tool is Gradle. Maven plays a
projects. We will only provide a small glimpse into Maven; just enough to fulfill the needs of the
Netbeans readily contains Maven, but you may also install Maven separately by e.g. following the
instructions provided on Maven homepage or in Linux by using the
system’s package manager. If Maven has been installed properly, you should be able to run it by
issuing the command mvn on a command line prompt.
A Maven project consists of mainly two things: a project configuration file named pom.xml,
which is stored in the project’s root directory, and source files, which are stored under
subdirectory src. Java source files actually reside in subdirectory src/main/java in a
usual subdirectory hierarchy based on packages. E.g. a code file SomeClass.java defined to be
in the package com.example would have file path src/main/java/com/example/SomeClass.java.
Like the file suffix suggests, the project file pom.xml describes the project properties in XML
format. If you are not yet familiar with XML, it is a good idea to learn its basic features e.g by
reading the Wikipedia article.
Below is an example of an almost minimal Maven project file:
<?xml version="1.0" encoding="UTF-8"?>
pom.xml must contain at least the following parts:
A project root element (begins with a <project> tag and end with a </project> tag).
All elements listed below are inside the root element.
A modelVersion element whose value should at present always be 4.0.0.
This tells which Maven standard (or “model”) the project file corresponds to. The current
standard is 4.0.0.
A groupId element that tells the group of the project.
Maven uses this information to group projects in a hierarchical manner (in a bit similar manner
how packages group code files).
An artifactId element that tells the name of the project.
A version element that tells the version of the project.
This would usually be incremented as the program is developed further and further. E.g. version
1.0 could be followed by version 1.1 or version 2.0, and so on.
The preceding project file also included a packaging element that defines what type of a
package Maven should generate; the value jar specifies that the program’s compiled class files
and possible other resources will be packed into a so called JAR file (this would also be Maven’s
default behaviour). This is discussed further below. The end also includes a properties
element that declares that source files use UTF-8 character encoding, Java source files are
compatible with Java version 17, and that the Java compiler will generate class files compatible
with Java version 17. You should use Java version settings that are compatible with your installed Java
environment (the project cannot use a higher version than what the environment supports; lower
versions can be used).
If you create a new Java with Maven/Java Application project in Netbeans, it will automatically
create a project file that is quite similar to the example file given above. You can find the
project file e.g. as an entry under the “Project files” folder of the project view pane in the
left side of the Netbeans main window.
You may build a maven project either by using an IDE that supports Maven or manually on the command
line. Some IDE’s (e.g. Netbeans) have built-in Maven support, but others (e.g. VS Code) require
installing a separate plugin.
Maven’s build process consists of multiple phases. Some of the main phases are:
compile: Compiles all source files under the project’s src subdirectory.
test: Performs automated tests with the compiled program (if such tests have been defined).
package: Packages the program into a distributable format, such as a JAR file.
install: Stores the package into Maven’s local repository.
E.g. in Linux Maven might store a package in the directory .m2/repository under the user’s
home directory. Maven by default prints out information about the name and location of the
This was only a partial list of Maven’s build phases.
A maven project can be built on the command line by issuing a command of form mvn phase, where
phase specifies the phase we want to execute. The listed phases are always executed in
succession in such manner that executing a phase entails executing also all earlier phases. E.g.
mvn compile compiles the project, mvn test first compiles and then tests, and
mvn package first compiles, then tests and finally packages it.
Maven by default places the compiled class files into the subdirectory target/classes. Java
class filess will follow the usual directory hierarchy based on their packages. If a project is
packaged e.g. into a JAR file, Maven will place the package into the root of the target
subdirectory. The name of the created package is by default derived from the information defined in
the project file: it is typically named in the form artifactId-version.jar.
The Run/Build project -command offered by Netbeans by default corresponds to issuing the command
mvn install. Since install is a later phase than package, also it will package the
program into the target subdirectory.
Java compiler tools support packaging the files of a program (or a class library) into a sigle file
(a JAR file) that can then be conveniently distributed to end users. A JAR file contains all
compiled class files, and possibly also some other resources, of the program, and is actually just
a ZIP file that has been renamed to use the
file suffix “.jar”. Therefore it is e.g. possible to use general ZIP tools to inspect, extract
or modify the contents of a JAR file.
The Java compiler suite contains a command line program jar that can package already compiled
class files etc. into a JAR file. We will not discuss this program further. Using Maven will
suffice in this course.
A program that has been packaged into a JAR file can be executed by giving the switch -jar and
the JAR file name to the Java virtual machine. For example java -jar program.jar would execute
execute a program that has been packaged into the JAR file program.jar.
java -jar program.jar
Java class libraries are practically always distributed as JAR files. If we want to execute a
program that relies on some classes or interfaces provided by some JAR file library.jar, Java
needs to be able to find the library file. The file must be either placed into a directory that
Java would anyway inspect (its own internal class directories and the current working directory) or
we must separately specify with a “-cp” switch a class path that leads to the file. For example
java -cp /some/directory/library.jar MyClass
would execute the class MyClass in such manner that Java searches class files required during
program execution from all its internal directories and additionally from the JAR file
library.jar located in the directory /some/directory. A class path definition can incude
also several paths and/or JAR files by separating them with colon (Linux, Mac) or semicolon
(Windows) characters. E.g. on Linux the execution
java -cp /another/directory/:.:/some/directory/library.jar MyClass would direct the Java
virtual machine to search class files from the directory /another/directory, the current
working directory ., and the JAR file library.jar in the directory /some/directory.
java -cp /some/directory/library.jar MyClass
java -cp /another/directory/:.:/some/directory/library.jar MyClass
One of the leading motives for using Maven is its capability to fetch external class libraries from
the internet. Java’s own class libraries are extensive but naturally cannot cover all our potential
needs. If there exists an external Java library that offers some functionality we would like to
use, it is higly likely that the library can be found from Maven’s central repository that provides
access to even millions of libraries. If this is the case, then we can import the library into a
maven project by simply adding a corresponding dependency definition into the project file
pom.xml. When we then build the project, Maven will automatically download the defined package
from the internet and the project can then use its classes and interfaces in a very similar manner
as how Java’s own class libraries are used.
A little further below is an example project file that contains a dependency definition: the project
file now contains also a dependencies element that in turn contains dependency elements that
list the dependencies of the project. The example below defines only one dependency: the jdom2
library that offers tools for processing XML data. A dependency definition specifies the
groupId, artifactId and version of the library. These three values allow Maven to
identify the exact library and version that should be fetched. This also is the reason why all
Maven projects have to specify these three values: if our own project would be published as a
library in Maven’s central repository, end users could import our library by specifying the three
values groupId, artifactId and version in a dependency definition in their own Maven
Maven central repository
You may wonder how we can know what dependency definition values should be used in order to
import a certain library? Quite often the documentation of the library (which we perhaps found
via an internet search engine etc.) describes the required Maven dependency definition. In any
case we can also search the library from Maven’s central repository, which offers a search page
https://search.maven.org/. The central repository e.g. lists
different available library versions, and the information for a certain version also describes
the corresponding Maven dependency definition.
<?xml version="1.0" encoding="UTF-8"?>
Importing jdom2 as a dependency is not the only new addition in the above example: it now also
includes a build element that contains definitions of plugins that we want Maven to use during
the build process. The example includes one such plugin element, which sets the project to use
a plugin called onejar. This plugin offers a convenient feature that packages also external
libraries into the JAR file. Maven would otherwise package only the project’s own class files etc.
into the JAR file, and then an end user would need to have both the JAR file of the project and
the JAR files of any required external libraries in order to be able to execute the program. When
we use onejar, the packaged JAR file will be self-sufficient. There will actually be two JAR files:
one is the default one without external libraries and the other one contains also external
libraries. The latter is by default named by adding the part “one-jar” into the default JAR file
name. E.g. if we would use the preceding project file, the command mvn package would create the
JAR files target/example-1.0.jar and target/example-1.0.one-jar.jar.
A onejar plugin definition contains one value that we should usually define explicitly for
each different project: the mainClass element. It defines the main class of the project, that
is, the class from whose main funtion program execution will start. E.g. the above example
defined the project’s main class as fi.tuni.prog3.example.ExampleMain. This definition is
required in order to be able to execute the program simply as java -jar program.jar, that is,
without a separate parameter that specifies the class from whose main function program
execution should start. But note that a project does not have to include a main function at all
if it is intended to be used as a class library.
If you use the onejar plugin without defining a main class, or if you want to start program
execution from some other class of the project, it is possible to provide the main class with a
command line switch of form -Done-jar.main.class=MainClass, where MainClass is the main
class (including the package prefix, if the class has any). For example
java -Done-jar.main.class=com.example.SomeClass -jar program.jar would start program execution
from the class SomeClass that is contained in the JAR file program.jar and belongs to the
java -Done-jar.main.class=com.example.SomeClass -jar program.jar
Programming demo (duration 43:49)