Do I need to have a Parent declaration in my POM.xml? - maven

I've declared my project as a pom.xml to define the parent, and it triggers a reactor build of all the included modules. Everything builds fine and works as expected. It builds in the right order, all the tests run correctly, and I get my expected output.
One of the projects is a shared library. I don't want to add a <parent> declaration here, so I didn't. It all still works.
My Question: do I need to bother adding a parent project declaration in any of my sub-projects? What are the pros and cons of having a two-way relationship between the projects? If I don't add the declarations, am I going to make it harder later when something stops working?
Rephrased into a single question: why bother with <parent> configuration in module pom.xml files?

Your question is related to the difference between Project Inheritance vs. Project Aggregation. The <parent> reference defines the inheritance relationship. The <modules> section in the parent pom.xml defines the aggregation. They are different.
If you do not have the <parent> configuration in the module pom.xml, it will not inherit the parent pom.xml configuration. So let's say you define the version of a dependency in the parent pom in the <dependencyManagement> section, the module pom.xml without parent reference will not inherit that. Or if all your child modules need to use a common library, you can define the dependency in the parent pom.xml. However, the module pom.xml without the parent reference will not inherit that dependency either.
For details, please check out Project Inheritance vs Project Aggregation

It depends on how you configure your build. If you have a correctly configured parent pom, basic information like version and groupid can be shared between your projects.
You can define the project wide configuration information that should be shared in all the modules in the project. For example:
<modelVersion>4.0.0</modelVersion>
<groupId>groupd.id</groupId>
<artifactId>artifact.id</artifactId>
<packaging>pom</packaging>
<version>version</version>
With that in place, you do not have duplicate that information in the module projects. The same information can be referenced like so:
<parent>
<groupId>group.id</groupId>
<artifactId>artifact.id</artifactId>
<version>version</version>
</parent>
Remember that the parent pom can be used to shared more information than specified above. You can do dependency management, plugin management and even define re-usable profiles.

Related

Maven: "dependency vs module "

I would like to know the difference between the two. From what I understand the dependency needs a version etc but modules can be defined without the version and it takes the parent's version. Is there more to it?
A dependency and a module are different concepts.
From the Maven book about dependencies:
Maven can manage both internal and external dependencies. An external dependency for a Java project might be a library such as Plexus, the Spring Framework, or Log4J. An internal dependency is illustrated by a web application project depending on another project that contains service classes, model objects, or persistence logic.
Put simply, a dependency is saying: "To build my project, I need to use this library".
A dependency in Maven is defined by its coordinates, that are made of 4 elements:
groupId: The groupId groups a set of related artifacts. It generally resemble a Java package name. For example, the groupId org.apache.maven is the base groupId for all artifacts produced by the Apache Maven project.
artifactId: The artifactId is the project main identifier. When you generate an artifact, this artifact is going to be named with the artifactId. The artifactId, groupId combination must be unique. In other words, you can't have two separate projects with the same artifactId and groupId. Furthermore, you can't have the same artifactId for a given groupId.
version: When an artifact is released, it is released with a version number, such as "1.0", "1.1.1", or "1.1.2-alpha-01". You can also use what is known as a snapshot version for a component which is under development, like "1.0-SNAPSHOT".
classifier: A classifier is not needed and is generally not used. It is only relevant when you need to produce several artifacts from a single project: it then serves as a distinction in the file names, that otherwise would be made simply with the artifactId and version and thus conflicts.
In the POM, it looks like this:
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
<dependency>
<groupId>org.some.project</groupId>
<artifactId>my-project</artifactId>
<version>4.0</version>
</dependency>
...
</dependencies>
...
</project>
This declares a dependency to the my-project library identified by the given coordinates.
A module is used in the context of multi-module Maven project. From the Maven book:
A multimodule project simply manages a group of other subprojects or modules. [...] When setting up a multimodule project, you are simply telling a project that its build should include the specified modules. Multimodule builds are to be used to group modules together in a single build.
Put simply, having a module is saying "To build my project, I need to build this project".
In the POM, this is done like this:
<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
https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.codehaus.mojo</groupId>
<artifactId>my-parent</artifactId>
<version>2.0</version>
<packaging>pom</packaging>
<modules>
<module>my-project</module>
<module>another-project</module>
</modules>
</project>
You are saying that this project, identified by org.codehaus.mojo:my-parent:2.0:pom, declared 2 modules which are my-project and another-project. Thus, when you build my-parent, those two modules will also be built.
Conceptually they're different, but they go hand-in-hand as well.
All of them parents, modules and libraries are referenced, by convention, using a unique name composed of a group-id, artifact-id and version. Unless you need otherwise (seldom happened to me) a module can indeed inherit its version from the parent but you do have the option of changing it.
A maven module is like a sub-project of your project. It allows you to separate a big projects into smaller parts which can be managed individually, and in the end aggregated to build whatever you require. We could picture a car as the end product, being composed of several modules such as engine, wheels, chairs etc.
A dependency is a library your project or module requires to compile and/or function. Coming back to our car, it's true that it requires an engine module to function. However, the current version of the engine itself requires a certain type (version) of pistons to run correctly. Too big and they won't fit, too small and it won't work at all.
Applied to a java project, you can imagine having several modules which access a DB, call some web services, provide an UI, all of them linked together by their parent. Also the DB module will probably require a certain DB driver (MYSql, Oracle, etc), matching the version of the DB you're using, and the web service module an HTTP library, and so on.

Avoid referencing parent pom in maven multi module project

My multi module project is made of public (open source) and private (undisclosed) modules. I need to create a master-all pom file referencing master-public and master-private, so that some plugins & commands are aware of all projects (e.g. cobertura). master-all has thus to be private as it references master-private.
The problem is that master-public should reference its parent master-all which is private, so users of public modules only won't be able to build them:
<groupId>group</groupId>
<artifactId>master-public</artifactId>
<parent>
<groupId>group</groupId>
<artifactId>master-all</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
Nesting master-public in master-private could be a solution for maven, but will be a mess for git.
Is there a clean way to do this?
You can have your master-private reference your master-public. But in my experience, it is best to keep them completely separate. Eventually, the master-public will be tuned more to open source, possibly deploying to Maven Central, while the master-private will deploy to your internal repository and possible have some special settings that only make sense in your enterprise environment. Copy whatever you absolutely need from your master-private to your master-public and disconnect the two.

Maven Multi Module Project

I havent used Maven extensively
Presently have 5 different maven projects , Each has a different pom.xml. As of now there is dependency relationship between them , each one points to other in < dependency > if needed.
Presently the thing we dont like are
When we release a child projectA , then we need to manually modify all projects having projectA as a dependency to use new version. Saw Maven has a version plugin , not sure how that will help.
As a solution I want to have a cleaner organization between poms , and possible avoid above issue.
What i thought is ( may be incorrect )
Where fat arrow represents Parent Child relationship and a thin arrow represents sub-module. But this does not seem to be working, see code and errors below
Child Project 2 pom
<groupId>ChildProject2</groupId>
<artifactId>ChildProject2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>Parent</groupId>
<artifactId>Parent</artifactId>
<version>${parent.version}</version>
<relativePath>../Parent/pom.xml</relativePath>
</parent>
<dependencies> ... </dependencies>
ChildProject2 - Error
Project build error: Non-resolvable parent POM: Failure to transfer Parent:Parent:pom:${parent.version} from http://repo1.maven.org/maven2 was
cached in the local repository, resolution will not be reattempted until the update interval of central has elapsed or updates are forced. Original error:
Could not transfer artifact Parent:Parent:pom:${parent.version} from/to central (http://repo1.maven.org/maven2): Illegal character in path at index 45:
http://repo1.maven.org/maven2/Parent/Parent/${parent.version}/Parent-${parent.version}.pom and 'parent.relativePath' points at wrong local POM
Parent pom
<groupId>Parent</groupId>
<artifactId>Parent</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<parent.version>0.0.1-SNAPSHOT</parent.version>
</properties>
<modules>
<module>../ChildProject2</module>
<module>../ChildProject1</module>
</modules>
<dependencies> ... </dependencies>
GrandParent2 pom
<groupId>GrandParent2</groupId>
<artifactId>GrandParent2</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>pom</packaging>
<properties>
<grandparent2.version>0.0.1-SNAPSHOT</grandparent2.version>
</properties>
<modules>
<module>../Parent</module>
</modules>
<dependencies>... </dependencies>
ParentMain.java
public class ParentMain {
public static void main(String[] args) {
DocumentFactory df = new DocumentFactory();
ChildProject1Main cp1 = new ChildProject1Main();
ChildProject2Main cp2 = new ChildProject2Main();
}
}
ParentMain - Errors
ChildProject1Main cannot be resolved to a type
ChildProject1Main cannot be resolved to a type
I am currently using Maven Version 2.2.1 (open to upgrading if this can be solved using upgraded maven version)
One of the comments below says can solve this using " CI tools out there such as Jenkins and TeamCity" .. any pointer (examples) how to solve this using Maven ( and or Hudson )??
What am i doing wrong , how to get best design for such project dependencies
The first question I thought of when I saw this diagram was, "Why would the business logic have any kind of dependencies on submodules?" Two thoughts sprung to mind, and I'll go through each of them and what you shouldn't be doing to repeat these.
Tightly coupled code. This manifests itself in code duplication or the large class/method smell.
You want your code to be modular, such that a project only depends on what it needs to in order to compile and run without error.
Illogical code hierarchy. This (eventually) manifests itself as circular dependencies, or dependencies that suddenly go missing when <exclude> blocks show up.
You want the lines of what depends on what to be explicit, such that your code hierarchy is well laid out.
I'm going to take your arrows in one cardinality to mean that a project depends on another, so it makes sense that the UI and CLI depend on the Business Logic to function. It also makes sense that Business Logic can depend on the children modules to do some other function not quite related to the core.
What doesn't make sense is that these children models also depend on Business Logic. The children modules should be unique enough that they do not need to depend on anything from Business Logic; if they do, then perhaps they should live there instead.
As for the versioning - there are CI tools out there such as Jenkins and TeamCity that can aid you with that problem. The thrust would be to have that set up in such a way that it occurs independent of human intervention/error.
How do I tell Maven to use the latest version of a dependency?
Take a look at the above thread. I like the answer by Adam Gent to use the versions plugin to update versions in your poms in jenkins. I agree with him that maven and continuous deployment are a particularly poor match.
So use that and a simple parent pom for any shared configuration (plugins, dependencies, etc) but don't make them multi module projects and version and release the parent pom as an independent thing.

How can I efficiently declare provided scope dependencies in maven multi-module builds?

I have a maven multi-module pom which builds a war. I want to declare a provided scope dependecy on jsp-api in the parent pom. Maven docs suggest that dependencies declared as provided are not transitive, so:
Do I therefore need to go through all the sub-module poms and declare a provided dependency? There are ~40 modules in the project and it's not immediately clear which will need the dependency, so this seems like quite alot of effort to achieve not very much and I am lazy. How are you handling this situation in your projects?
--Edit--
So for others reference this was happening because the parent pom was defining all dependencies in a dependencyManagment section. I'd not come across this before but it helps with cutting down duplication of complex dependencies with excludes or other non-trivial attributes. It also overrides the inheritance mechanism. As I understand it then, a good rule of thumb is to only use it to solve a problem don't just chuck all your dependencies in there as the author of this pom had done. Perhaps a suitable maven expert could confirm this.
Even though provided scope dependencies are not transitive they may be inherited. That is to say, if you have module A with a provided scope dependency, and module B has a dependency on A, module B will not implicitly have the provided scope dependency. However, I believe that if module C has module A as a parent pom, it should inherit that dependency as normal.
You can verify this behavior yourself by running mvn help:effective-pom on one of the child poms, the effective-pom goal should give you a fully resolved view of the pom you run it on, taking into account inheritance, equivalent to what maven will actually use when it runs. If the <dependency> shows up there (as it seems to in my experiments) you should be fine specifying the dependency only in the parent pom.

Maven include another pom for plugin configuration

is there a way to include another pom or information in a maven pom ?
I have several poms which are basically not related or have different parent poms. Nevertheless for packaging it is required to have a Manifest identical to all projects.
So currently I have in a pom:
<plugin>
<artifactId>maven-assembly-plugin>
<!--- .... -->
<archive>
<manifestEntries>
<build-date>....</build-date>
<build-nr>.....</build-nr>
etc etc
I would like to avoid to paste this configuration to all severall poms.
So how can I share the configuration of a plugin without inheritance ?
Thanks
One way to do this is using pluginManagement section. plugin configurations can be defined in this section in a parent pom and will be available to inherited poms to be used as is or overridden.
Here is the relevant maven documentation. In your specific case, you would need to organize your projects/poms suitably.
The only correct answer is to use inheritance. Have an inherited ancestor with this configuration in it. Since you have existing parent POMs, these must inherit from this new parent. If this isn't possible then rethink the hierarchy of your Maven projects, or else you'll have to copy and paste the same configuration into each file and add a comment indicating the section must not be modified / must be maintained consistently with [insert list of projects here].
TLDR; Inheritance is designed specifically to resolve situations such as yours. If you can't use it then don't try to hack around it - either restructure your POMs or copy and paste!

Resources