Perfect maven. Part 2: project structure

Published on December 12, 2017

Perfect maven. Part 2: project structure

  • Tutorial

This is the second article about Maven and its use for organizing my projects. The purpose of this article will be the structure of the project under the control of the maven. You will not find any special revelations, rather a set of general rules for my projects. The first article can be read here .


Project structure


As I said, I will not describe here the typical structure of the project on the maven - you know it or you can easily find it at the link: Standard Directory Layout . In this part I will focus on the features that I apply in my projects, so:


Modules


Almost any of my projects has several modules. Practice shows that when it is necessary to add another module to the project it is much easier to do in the case of an initially modular project. In my projects, there are 3 types of “modules” - POM (always one), several development modules with code, and BOM - if maids. there are more than one modules. In principle, POM is not a module in the understanding of maven, but I always design it almost like a “module” (I will show below). The result is something like this:



General principles for all POMs - they contain a minimum of information necessary for building a project, all versions, all plug-in settings that are not specific to this project are in a super ("corporate") POM. All “modules”, except for the project POM, contain a link to the local version of the parent relativePath.

Project POM


Let's start with the project POM. I almost always put it in a separate directory called pom. I do this for several reasons:


  • Import projects into Eclipse. This is the easiest way to avoid importing modules together with the project POM.
  • Files related to the whole project (for example .htignore, in the picture above) and the “project” imported into the IDE (for example .settings, which generates Eclipse for each “module” upon import) are separated.
  • It’s so visually easier for me to perceive it as a “module” of a project.

The project POM contains a link to the super POM, a list of modules, the version of projects on which it depends (not libraries of third countries, namely projects that are in parallel development in this company) and the definition of the version for modules and projects (dependencyManagement). Here is a typical POM for a small project:


<?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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>org.jresearch.pom</artifactId>
        <groupId>org.jresearch</groupId>
        <version>29-SNAPSHOT</version>
    </parent>
    <groupId>org.jresearch.commons.base.resources</groupId>
    <artifactId>org.jresearch.commons.base.resources.pom</artifactId>
    <version>1.0.43-SNAPSHOT</version>
    <packaging>pom</packaging>
    <modules>
        <module>../api</module>
        <module>../impl</module>
        <module>../test</module>
        <module>../bom</module>
    </modules>
    <properties>
        <jrs.open.base.domain.ver>1.0.34-SNAPSHOT</jrs.open.base.domain.ver>
    </properties>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jresearch.commons.base</groupId>
                <artifactId>org.jresearch.commons.base.domain</artifactId>
                <version>${jrs.open.base.domain.ver}</version>
            </dependency>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.test</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

In this example: the
version of the project on which it depends


    <properties>
        <jrs.open.base.domain.ver>1.0.34-SNAPSHOT</jrs.open.base.domain.ver>
    </properties>

and versioning for modules and projects


<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jresearch.commons.base</groupId>
                <artifactId>org.jresearch.commons.base.domain</artifactId>
                <version>${jrs.open.base.domain.ver}</version>
            </dependency>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.api</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

Why is this needed? To completely eliminate the use of versions in development modules. With this configuration, all versions are fixed in the super POM (for external libraries) and in the project POM (for the project itself and its dependencies on internal projects). This not only makes the POMs in the modules cleaner, but also necessary for the release of the process that I use.


BOM POM


This is “ bill of materials ” - a list of artifacts that the project exports. In my projects, it appears if the number of development modules is more than one. This allows you to manage dependency versions between internal projects with just one entry in a section dependencyManagement.
BOM example:


<?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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>org.jresearch.commons.base.resources.pom</artifactId>
        <groupId>org.jresearch.commons.base.resources</groupId>
        <version>1.0.43-SNAPSHOT</version>
        <relativePath>../pom/pom.xml</relativePath>
    </parent>
    <packaging>pom</packaging>
    <artifactId>org.jresearch.commons.base.resources.bom</artifactId>
    <name>JRS-COMMONS: Base resource (DAO) BOM</name>
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.api</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.impl</artifactId>
                <version>${project.version}</version>
            </dependency>
            <dependency>
                <groupId>org.jresearch.commons.base.resources</groupId>
                <artifactId>org.jresearch.commons.base.resources.test</artifactId>
                <version>${project.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>
    </build>
</project> 

Module with code


The most primitive POM. Includes a link to the project POM, artefactId, a list of dependencies without versions. If necessary, the build section with links to plugins. Version and groupIdare inherited from the parent POM.
Example:


<?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/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <artifactId>org.jresearch.commons.base.resources.pom</artifactId>
        <groupId>org.jresearch.commons.base.resources</groupId>
        <version>1.0.43-SNAPSHOT</version>
        <relativePath>../pom/pom.xml</relativePath>
    </parent>
    <artifactId>org.jresearch.commons.base.resources.api</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.jresearch.commons.base</groupId>
            <artifactId>org.jresearch.commons.base.domain</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.code.findbugs</groupId>
            <artifactId>jsr305</artifactId>
        </dependency>
        <dependency>
            <groupId>joda-time</groupId>
            <artifactId>joda-time</artifactId>
        </dependency>
    </dependencies>
</project>

Artifact name


groupIdthis is the name of the package in Java for this project - recently it has become almost the standard. C artifactIdis a bit of a miracle, for my projects I always take the group name plus the module name, something like this:


<artifactId>org.jresearch.orika.spring</artifactId>

Why? The name of the final artifact must be unique (all too often everything is dumped into one directory), I brought out the very idea of ​​the eclipse world - that’s how plugins are called there. At first, it’s unusual, but it’s quite unique, it’s very easy to come up with it, when you see a directory by name you can very quickly find an artifact in the repository and source control.


Why not use it finalNamein super POM (eg <finalName>${ groupId}.${artifactId}-${version}</finalName>)? This happened historically, at the dawn of the mavenization, a lot of plugins ignored the rules, and it was easier to write it with your hands. Now, probably, this is not so.


Following this convention with names is optional. The main thing is the uniqueness of the name of the final artifact.


General principles in structure for my projects.


  1. Dependency and plugin versions only in super or project POMs
  2. All modules inherit the version and group that are defined in the project POM.
  3. If I am firmly (146%) sure that the project will contain only one module with code, I do the classic maven project (eg https://bitbucket.org/JRS/open-base-util/src )
  4. If I know that there will be several modules, I immediately add the bom module (eg https://bitbucket.org/JRS/open-base-resources/src )
  5. If not sure, then a project from one module without a BOM (eg https://bitbucket.org/JRS/open-base/src )
  6. artifactId is always groupId + module name
  7. directory structure for the project: the root directory is the name of the project (short), pom is the directory for the project POM, bom is for the BOM POM, the rest are directories by the name of the modules.
  8. relativePath- in all “modules”, except for project POM, one maven project is one project in source control. All communications between projects only through the maven.

According to the structure of projects, this is probably all.