Note
Maven is declarative, not procedural. By default it is in XML, but you can write it in other languages.* We will use YAML.
Tip
Maven works on a principle of a “tree of trees” of build configuration overlaid over each other, which then create an effective tree - so called POM (project object model).
Tip
There is a tree of modules, which usually more less correlates to the directory structure; each module contributes another overlay POM to what it inherits from the ancestors.
Let’s have a project. It has a root and 1 module.
itsspush-root
itsspush-server
Each of these modules has a POM, project object model, which is a tree of configuration.
Imagine 2 YAMLs. Let’s call them itsspush-root
and itsspush-server
. (For brevity, these snippets are not full POMs, and the project
is added for better optics.)
project:
groupId: com.mycompany.itsspush
artifactId: itsspush-root
properties:
db_user: abc123
project:
artifactId: itsspush-server
Now let’s put them in relation: Make the itsspush-root
to be the parent of itsspush-server
.
project:
parent: itsspush-root <-- NEW
artifactId: itsspush-server
During a build, Maven merges these trees for each node. Parents are overlaid with children.
Therefore, the effective POM of itsspush-server
results into:
project:
groupId: com.mycompany.itsspush
parent: itsspush-root
artifactId: itsspush-server
properties:
db_user: abc123
Tip
The effective POM controls executions of plugins - when, how, and on what they act.
The pom.xml files contain 2 kinds of information: General project description, like artifactId
, and plugin configurations. The General description may be used by plugins as default values.
Otherwise, the plugins are configured in their respective plugin
section.
build:
plugins:
plugin:
artifactId: maven-flyway-plugin
configuration:
jdbcUrl: ...
plugin: ...
Like everything, these values are also merged - inherited from the parent, and overlaid by the children. That means, a plugin which executes in a parent also executes in all children (unless an overlay disables that).
Depending on project: / packaging: ...
, some default plugin executions are pre-set.
E.g. packaging: jar
provides Java compilation via maven-compiler-plugin
, etc.
Tip
Maven handles the aspect of dependencies, which determines the class paths, but also the order of the modules during build.
The library dependencies point to an artifact in some repository, and are usually added to a compilation or runtime class path.
The “project dependencies” point to a module within the project, and besides class path, they are used to compute the order of modules in a build.
Tip
Maven has a default list of build phases.
Being a build tool, Maven designers identified a list of generic build phases, which mostly fits any project module build.
The key word is module: Usually, when you feel these phases are not enough, you should split your module into sub-modules. This is one of the most useful effects of Maven on the quality of builds.
Tip
Properties
The POM also contains properties, a Map<String, String>
. And like everything, it is overlaid by child POMs.
Properties can be used (almost) anywhere where you can place text - including other property values.
Propeties can be defined in the pom.yaml
, as env vars, in a properties file, as a CLI input, or even dynamically by plugins. They overlay in that order.
properties:
db.user: granit
mvn … -Ddb.pass: myPasswd123
Tip
Profiles
One more overlay mechanism is a profile. Within one pom.yaml, multiple profiles may be defined; they contain parts of the module’s POM. Upon activation, all the active profiles are merged into the module’s POM, in the order of appearance in the file. (The resulting merged module’s POM then serves as what is passed to the children.)
profiles:
- id: useGranit
plugins:
artifactId: docker-maven-plugin
## ... the rest of config to build, start and stop Granit Docker image.
mvn … -PuseGranit
Tip
Local config: ~/.m2/settings.xml
To keep your local stuff local, certain things go to profiles in settings.xml: Passwords, user names, local paths, keys, etc.
profiles:
- id: nexxiot
properties:
jfrogRepo.key: ey...
jfrogRepo.url: https://nexxiot.jfrog.com/...
Note
That’s it 😄
Seriously. There’s not much more. The concepts above are incredibly powerful, and when you wrap your head around them, you can solve 99.5 % build needs in a concise way, not repeating yourselves; and 90 % will be elegant.
* Alternative syntaxes are possible via Maven Polyglot. Some tools may only work with XML.