The Project Object Model - POM
3.1 Description
3.2 Sample file
3.3 POM Syntax
3.4 Standard directory structure
3.5 Parent POM
3.6 Dependencies
3.6.1 External dependencies
3.6.2 Snapshot dependencies
3.7 Exclusions
3.8 Aggregation
3.9 Profiles
3.10 Best practices
3.1 Description
POM is an xml file where a Maven project is described, configured and customized like the web.xml file for the Java web applications, Makefile or an Ant build.xml.
POM contains all the parameters and settings shared across the company - multiple projects, developers, paths, maven plugins, many dependencies with different versions.
In POM unique coordinates can be assigned to the project (groupId, artifactId, version), the attributes of the projects, developers or persons that contribute to the project, dependencies are described.
In conclusion by POM file in Maven defines the model for every project.
By using this approach with POM, Maven can be considered a declarative build system declaring what we would like to have as result not what to do(imperative build system).
Like in Java where all the objects have parent java.lang.Object, in Maven all POMs have parent in Maven Super POM.This POM contains all the default information and it is not necessary to be repeated with every new POM.
3.2 Sample file
<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> <groupId>com.company.insurance</groupId> <artifactId>carAccident</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name>carAccident</name> <url>http://maven.apache.org</url> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> </dependencies> </project>
3.3 POM Syntax
The POM filenamed always pom.xml is located in base directory of a Maven Project.
POM can be divided in more logical units.
Project versions
Maven project version represents a number used to order the releases for a project. This number is composed of other three numbers separated by dots every one of the number having an important role.
<major version>.<minor version>.<incremental version>-<qualifier>
Qualifier can be major, minor or incremental and is separated with hyphen “-“. It can be beta or alpha. The qualifier is use to enhance milestone builds.
If these standard requirements are followed then Maven will sort the release versions of the projects correctly.
SNAPSHOT versions
If the version contains the string “SNAPSHOT” Maven will add to this token date and time converted to UTC.
For example:
0.1-SNAPSHOT will be extended by Maven to 0.1-20141003-120305-1 this means the time for release 12:02 AM on October 3rd, 2014 UTC.
A project that depends on SNAPSHOT is not stable. All the SNAPSHOT versions of the dependencies should be resolved on release versions when a project is released. SNAPSHOT versions are only for development.
We can visualize the pom.xml with the command line
mvnhelp:effective-pom
or declaring help:effective-pom as goal in Eclipse. This will help to replace references (type of ${..} ) to properties with its values.
POM Relationships
POM relationships can be grouped in the following way:
- Project coordinates
- Inheritance
- Dependency management
- Modules
- Project level properties
Project metadata
- Name
- Organization
- Developers
- URL
- Inception year
- Licenses
- Contributors
Build settings
- Properties
- Packaging
- Build
- Reporting
Build Environment
- Environment information
- Issue management
- Control integration
- Continuous integration
- Mailing list
Maven environment
- Prerequisties
- Repositories
- PluginRepositories
- Distribution Management
- Profile
- Profile activation
3.4 Standard directory structure
Maven projects have to follow a common strategy regarding the structure. The structure
has to contain two subdirectories:src and target.
- src
- main
- java
- resources
- webapp
- WEB-INF
- main
- test
- java
- resources
- target
The other directories are metadata (CVS or .svn) and other subprojects for a multi project.
The target directory is used to house all the output of a build (compiled classes, Jar files) .This directory is erased after the clean build phase. .
The src directory containsall the source for the building. It contains a subdirectory depending of the type of use
main- for main build artifact
test – for unit test code and resources
The java directory contains code for the application itself (under main) and java code for tests (under test directory).
The resources directory contains files with .properties extension, used for internationalization of the project or for properties variables and values (labels name or menu values).
The webappdirectory contains Java web application. This is the root for a web application and contains the subdirectory WEB-INFwhere is located the web.xml file descriptor and other files necessary for web development (css files, img files, javascript files).
3.5 Parent POM
For the Maven projects with more POMs, all the files inherit from the parent POM named too super POM. If no super POM is specified then POMs inherit from the base POM.
moduleParent pom.xml moduldeChild1 pom.xml moduleChild2 pom.xml moduleChild3 pom.xml
To declare explicit a super POM the files of the child modules have to contain <parent> tag.
Each subproject except the higher-level one should contain the following definition:
<project ...> ... <parent> <groupId>com.company.someApp</groupId> <artifactId>someApp</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../parentArtifactId</relativePath> </parent> ... <artifactId>someApp-web</artifactId> ... </project>
The child POM file overrides settings from the super POM file.
3.6 Dependencies
3.6.1 External dependencies
If necessary dependencies for a project are not available neither in central repository nor in remote repository or local repository then they can be called External Dependencies. The dependency can be located in the local machine and moved then to the lib directory. This type of dependencies are named external because are external to Maven repository system.
External Dependencies can be added to the POM as other dependencies. For example if a library will be added to a project in pom.xml it has to be specified:
- groupId ( name of the library)
- artifactId (name of the library)
- scope = system
- version ( respect the pom rules for version syntax )
- system relative path to the project location
For example if a local jar of typedateUtils ( necessary classes to format date and time ) and this jar does not exist in the any repository this jar can be added to lib folder ( should be created in src folder). The project will have now the following structure:
In POM this jar will be added as external dependency:
3.6.2 Snapshot dependencies
Snapshot dependencies are dependencies (jar files) which are currently under deployment. The snapshot dependencies are always downloaded in the local repository in order to have the latest version for the build.
See in the subchapter 3.3 POM Syntax the Snapshot versions paragraph how the snapshotare processed by Maven.
<dependency> <groupId>mydependency</groupId> <artifactId>mydependency</artifactId> <version>1.0-SNAPSHOT</version> <relativePath>${basedir}\src\lib\mydependency.jar</relativePath> </dependency>
In settings.xml file it can be configured how often Maven shall download snapshot dependencies from the central repository.
If the dependency snapshot exists already in the maven central repository or the remote repository of the project in settings.xml file it can be updated in the following way:
<profiles> <profile> <id>allow-snapshots</id> <activation><activeByDefault>true</activeByDefault></activation> <repositories> <repository> <id>snapshots-repo</id> <url>https://oss.sonatype.org/content/repositories/snapshots</url> <releases><enabled>false</enabled></releases> <snapshots><enabled>true</enabled></snapshots> <updatePolicy>interval:5</updatePolicy> </repository> </repositories> </profile> </profiles>
The updatePolicy tag was added in order to force Maven to check more than once per day updating the snapshots automatically – in this case at every 5 minutes.
From command line it can be used for updating the snapshots the following command:
mvn install –Uor mvn install –update-snapshots
The command forces Maven to check all snapshots in remote repository and update the local repository.
In Eclipse this option can be selected before build.
The mechanism is the following:
Project X
install to Local Repository X
deploy to Remote Repository ( common for project X and Y)
Project Y
Mvn -Uautomatically update snapshots in Local Repository Y from Remote Repository
3.7 Exclusions
Exclusions are necessary when different versions of the same JAR are fetched in the project. This can lead to classpath issues.
This problem appears when transitive dependencies (projects that depend on other projects) are fetched in the project.
To avoid this, the <exclusions> tag has to be added.
<dependency> <groupId>mydependency</groupId> <artifactId>project-x</artifactId> <version>1.0-SNAPSHOT</version> <exclusions> <exclusion> <groupId>mydependency</groupId> <artifactId>project-y</artifactId> </exclusion> </exclusions> </dependency>
3.8 Aggregation
Aggregation is used in multi-module project to centralize the build process of all the modules. Multi-module builds are to be used to group modules together in a single build.
It has to be created an aggregator project and to declare all the modules in its POM. During the build phase of the aggregator project all the modules already aggregated are built.
The ordering of the modules is not important. Maven builds first the dependencies and then the project.
Aggregation of other modules in Maven is used for:
- simplify the POM structure for the project modules by reducing the number of dependencies
- lettingmodule developers to have no concern about versions of common libraries
- centralizing control over versions
- simplify upgrading of versions of third party tools
- reducing the size of war files
– faster builds
– smaller transfers to servers
– faster application startup
- avoiding version conflicts at run-time.
<project ...> ... <groupId>com.myApp.something</groupId> <artifactId>something</artifactId> <version>1.0.0-SNAPSHOT</version> ... <modules> <module>someApp-lib</module> <module>someApp-domain</module> <module>someApp-web</module> </modules> ... </project>
3.9 Profiles
Profiles are declarations made in order to avoid some configurations with filesystem references.
In general Maven projects depend on the local repository to store the required data and don’t depend on the filesystem references.
For example at deployment one folder (with physically files images or pdf type) or sub-module can be provided from other system and it is not necessary that the archive( war) of the application to contain it .
Profiles are also a good solution when there are necessary different database connection parameters for the project environments (development, integration, test and production).
In conclusion with profiles the project will build in various environments from the developer machine to the continuous integration servers.
Profiles can activate or deactivate by some condition.
Profiles can be trigger
- from command – line
- Maven settings.xml file
- POM
From command line profiles are activate when –P flag is mentioned
mvn install –P !profile-a, !-profile-b
In the settings.xml file:
<settings> … <activeProfiles> <activeProfile>profile-a</activeProfile> </activeProfile>profile-a</activeProfile> …. </settings>
From POM.xml
<profiles> <activation> <property> <name>environment</name> <value>dev</value> </property> </activation> </profiles>
3.10 Best practices
Some general rules
Maven has to be learned gradually. It has a vertical slope learning curve.
Projects in Maven have to be named. It is hard with IDEs to distinguish between two unnamed projects.
The new created modules for a project have to be technical or business oriented layered.
Technical
<modules> <module>someApp-lib</module> <module>someApp-domain</module> <module>someApp-impl</module> <module>someApp-web</module> </modules>
Business oriented
<module>someApp-contract</module> <module>someApp-finance</module> <module>someApp-administrative</module> <module>someApp-hr</module> </modules>
Some rules for versioning
It is recommended that the versions of the modules to be inherited from the parent POM and changed at every release because it is necessary an additional effort (try to find if is a major, minor or incremental )to change individually the version of every module when one of such module has code changes.
In case of multiple SNAPSHOT dependencies it is recommendable to try to minimize its number.
Some suggestions for Maven profiles
The profiles have to be used to manage build-time variables not run-time variable and not alternative versions of an artifact. The use of profiles will increase complexity in all the building process.
Producing variant artifacts for a project with the help of profiles is in reality against the Maven convention - to produce only one artifact per project (eventually the second artifact for documentation).
The tag <activeByDefault> should never be used. This tag will activate a profile if no other profile is activated. This can lead to unexpected behavior. Activating a profile has to be done explicitly in POM adding the tag <activation>and !negation before the profile.
The profile will become active automatically whenever is not.
<profiles> <profile id=”noEnvironment”> <activation> <property> <name>! environment</name> <value>dev</value> </property> </activation> </profile> </profiles>
The build must pass when no profile has been activated. This practice is recommended in order to minimize the effort required for a build.