Maven dependency management

Dependencies are also important in the POM file. The previous project did not have any dependency, but this time we will use JUnit. Dependencies are defined in pom.xml using the dependencies tag. For example, the bubble sort module contains the following piece of code:

<dependencies> 
<dependency>
<groupId>packt.java9.by.example</groupId>
<artifactId>SortInterface</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
</dependencies>
The actual pom.xml in the code set you can download will contain more code than this. In print, we often present a version or only a fraction that helps the understanding of the topic that we are discussing at that point.

It tells Maven that the module code uses classes, interfaces, and enum types that are defined in these modules that are available from some repository.

When you use Maven to compile the code, the libraries that are used by your code are available from repositories. When Ant was developed, the notion of repositories was not invented. At that time, the developers copied the used version of the library into a folder in the source code structure. Usually, the directory lib was used for the purpose. There were two problems with this approach. One is the size of the source code repository. If, for example, 100 different projects used JUnit, then the JAR file of the JUnit library was copied there 100 times. The other problem was to gather all the libraries. When a library used another library, the developers had to read the documentation of the library that described (many times outdated and not precise) what other libraries are needed to use this library. Those libraries had to be downloaded and installed the same way. This was time consuming and error prone. When a library was missing and the developers just did not notice it, the error was manifested during compile time when the compiler could not find the class or even only at runtime when the JVM was not able to load the class.

To solve this issue, Maven comes with a built-in repository manager client. The repository is a storage that contains the libraries. As there can be other types of files in a repository, not only libraries, Maven terminology is artifact. The groupId, the artifactId, and the version number identify an artifact. There is a very strict requirement that an artifact can only be put into a repository once. Even if there is an error during the release process that is identified after the erroneous release was uploaded, the artifact cannot be overwritten. For the same groupId, artifactId, and version, there can only be one single file that will never change. If there was an error, then a new artifact is to be created with new version number and the erroneous artifact may be deleted but not replaced.

If the version number ends with -SNAPSHOT, then this uniqueness is not guaranteed or required. Snapshots are usually stored in separate repository and are not published for the world.

Repositories contain the artifacts in directories that are organized in a defined way. When Maven runs, it can access different repositories using https protocol.

Formerly, the http protocol was also used, and for non-paying customers, the central repository was available via http only. However, it was discovered that modules downloaded from the repository could be targets for men-in-the-middle security attacks and Sonatype (http://www.sonatype.com) changed the policy and used https protocol only. Never configure or use a repository with the http protocol. Never trust a file that you downloaded from HTTP.

There is a local repository on the developer machine, usually under the ~/.m2/repository directory. When you issue the mvn install command, Maven stores the created artifact here. Maven also stores an artifact here when it is downloaded from a repository via HTTPS. This way, subsequent compilations do not need to go out to the network for the artifacts.

Companies usually set up their own repository manager (the one that Sonatype, the company backing Maven, is providing Nexus). These applications can be configured to communicate with several other repositories and collect the artifacts from there on demand, essentially implementing proxy functionality. Artifacts travel to the build from the far end repositories to the closer ones in a hierarchical structure to the local repo and essentially to the final artifact if the packaging type of the project is war, ear, or some other format that encloses the dependent artifacts. This is essentially file caching without revalidation and cache eviction. This can be done because of the strict rules of artifact uniqueness. This is the reason for such a strict rule.

If the project bubble were a standalone project, and not part of a multi-module one, then the dependency would look like this:

<dependencies> 
<dependency>
<groupId>packt.java9.by.example</groupId>
<artifactId>SortInterface</artifactId>
<version>1.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
</dependencies>

If version is not defined for a dependency, Maven will not be able to identify which artifact to use. In the case of a multi-module project, version can be defined in the parent and the modules can inherit the version. As the parent is not dependent on the actual dependency, it only defines the version attached to the groupId and artifactId; the XML tag is not dependencies, but dependencyManagement/dependencies under the top-level project tag as in the following example:

<dependencyManagement> 
<dependencies>
<dependency>
<groupId>packt.java9.by.example</groupId>
<artifactId>SortInterface</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>

If the parent POM uses the dependencies tag directly, Maven is not able to decide if the parent depends on that artifact or some modules. When the modules want to use junit, they need not specify the version. They will get it from the parent project defined as 4.12, which is the latest from JUnit 4. If ever there will be a new version 4.12.1, with some serious bugs fixed, then the only place to modify the version number is the parent POM, and the modules will use the new version starting with the next execution of the Maven compilation.

When the new version, JUnit 5, comes out, however, the modules will all have to be modified because JUnit is not just a new version. Version 5 of JUnit is split into several modules and, this way, groupId and artifactId will also change.

It is also worth noting that the modules that implement the interfaces from the SortInterface module are eventually dependent on this module. In this case, the version is defined as follows:

<version>${project.version}</version>

That seems to be a bit tautological (it is, actually). The ${project.version} property is the version of the project and it is inherited by the SortInterface module. This is the version of the artifact that the other modules depend on. In other words, the modules always depend on the version that we are currently developing.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.157.197