Managing a Java code project with Maven¶
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.
Maven project structure¶
A Maven project consists of mainly two things: a project configuration file named
which is stored in the project’s root directory, and source files, which are stored under
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
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"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fi.tuni.prog3</groupId> <artifactId>example</artifactId> <version>1.0</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> </project>
pom.xml must contain at least the following parts:
projectroot element (begins with a
<project>tag and end with a
</project>tag). All elements listed below are inside the root element.
modelVersionelement 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.
groupIdelement 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).
artifactIdelement that tells the name of the project.
versionelement 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
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.
Buildind (e.g. compiling) a Maven project¶
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
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/repositoryunder the user’s home directory. Maven by default prints out information about the name and location of the stored package.
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
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
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
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
JAR files (Java Archive files)¶
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
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
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
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
., and the JAR file
library.jar in the directory
Fetching external libraries with Maven¶
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
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
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"?> <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/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fi.tuni.prog3</groupId> <artifactId>example</artifactId> <version>1.0</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>org.jdom</groupId> <artifactId>jdom2</artifactId> <version>184.108.40.206</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>com.jolira</groupId> <artifactId>onejar-maven-plugin</artifactId> <version>1.4.4</version> <executions> <execution> <configuration> <mainClass>fi.tuni.prog3.example.ExampleMain</mainClass> <onejarVersion>0.97</onejarVersion> <attachToBuild>true</attachToBuild> </configuration> <goals> <goal>one-jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build> </project>
Importing jdom2 as a dependency is not the only new addition in the above example: it now also
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
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
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
Programming demo (duration 43:49)