ChatGPT解决这个技术问题 Extra ChatGPT

Maven parent pom vs modules pom

There seem to be several ways to structure parent poms in a multiproject build and I wondering if anyone had any thoughts on what the advantages / drawbacks are in each way.

The simplest method of having a parent pom would be putting it in the root of a project i.e.

myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

where the pom.xml is both the parent project as well as describes the -core -api and -app modules

The next method is to separate out the parent into its own subdirectory as in

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/

Where the parent pom still contains the modules but they're relative, e.g. ../myproject-core

Finally, there's the option where the module definition and the parent are separated as in

myproject/
  mypoject-parent/
    pom.xml
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml

Where the parent pom contains any "shared" configuration (dependencyManagement, properties etc.) and the myproject/pom.xml contains the list of modules.

The intention is to be scalable to a large scale build so should be scalable to a large number of projects and artifacts.

A few bonus questions:

Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).

How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?

Edit: Each of the sub projects have their own pom.xml, I've left it out to keep it terse.

Do the modules each have their own pom as well? My project has a parent pom, but the modules each have a pom as well. (perhaps a fourth way to what u describe )
Ah, yeah, I'll edit and update. Each of the submodules has their own pom as well.
Just as an update, I can see an advantage of the second option is that it is easier to manage in Eclipse where the root pom.xml in the first and third example would be difficult to include if the sub modules are separate projects in Eclipse.

P
Pascal Thivent

In my opinion, to answer this question, you need to think in terms of project life cycle and version control. In other words, does the parent pom have its own life cycle i.e. can it be released separately of the other modules or not?

If the answer is yes (and this is the case of most projects that have been mentioned in the question or in comments), then the parent pom needs his own module from a VCS and from a Maven point of view and you'll end up with something like this at the VCS level:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
`-- projectA
    |-- branches
    |-- tags
    `-- trunk
        |-- module1
        |   `-- pom.xml
        |-- moduleN
        |   `-- pom.xml
        `-- pom.xml

This makes the checkout a bit painful and a common way to deal with that is to use svn:externals. For example, add a trunks directory:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks

With the following externals definition:

parent-pom http://host/svn/parent-pom/trunk
projectA http://host/svn/projectA/trunk

A checkout of trunks would then result in the following local structure (pattern #2):

root/
  parent-pom/
    pom.xml
  projectA/

Optionally, you can even add a pom.xml in the trunks directory:

root
|-- parent-pom
|   |-- branches
|   |-- tags
|   `-- trunk
|       `-- pom.xml
|-- projectA
|   |-- branches
|   |-- tags
|   `-- trunk
|       |-- module1
|       |   `-- pom.xml
|       |-- moduleN
|       |   `-- pom.xml
|       `-- pom.xml
`-- trunks
    `-- pom.xml

This pom.xml is a kind of "fake" pom: it is never released, it doesn't contain a real version since this file is never released, it only contains a list of modules. With this file, a checkout would result in this structure (pattern #3):

root/
  parent-pom/
    pom.xml
  projectA/
  pom.xml

This "hack" allows to launch of a reactor build from the root after a checkout and make things even more handy. Actually, this is how I like to setup maven projects and a VCS repository for large builds: it just works, it scales well, it gives all the flexibility you may need.

If the answer is no (back to the initial question), then I think you can live with pattern #1 (do the simplest thing that could possibly work).

Now, about the bonus questions:

Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).

Honestly, I don't know how to not give a general answer here (like "use the level at which you think it makes sense to mutualize things"). And anyway, child poms can always override inherited settings.

How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?

The setup I use works well, nothing particular to mention.

Actually, I wonder how the maven-release-plugin deals with pattern #1 (especially with the <parent> section since you can't have SNAPSHOT dependencies at release time). This sounds like a chicken or egg problem but I just can't remember if it works and was too lazy to test it.


That's very good as I can see how it scales. The svn:externals answers my concern about it being cumbersome.
@jamie Glad you find it helpful.
Could you elaborate on how-to make the "hack" work? I've got the trunks project and anticipate that you target the -pl option with "launch of a reactor build" but this presents as a problem when doing a release on the structure because this option does not pass from a build at root level neither can I place it in the option of the release-Plugin. Therefore the release:perform failes because it tries to work on the root-level pom...
The svn:externals hack is the most useful svn hack I have seen in a long time. Very helpful with projects that have per-project branching within the same repository.
Hi Pascal, How would you handle version# if projects which are mentioned in the modules section, doesn't use parent-pom as its <parent> but some-other-project-parent-pom? What versions # will we get for an artifact of such projects (version# of the artifact in <parent> section of those projects OR version# of the Project which lists these projects as modules)? stackoverflow.com/questions/25918593/…
c
cetnar

From my experience and Maven best practices there are two kinds of "parent poms"

"company" parent pom - this pom contains your company specific information and configuration that inherit every pom and doesn't need to be copied. These informations are: repositories distribution managment sections common plugins configurations (like maven-compiler-plugin source and target versions) organization, developers, etc Preparing this parent pom need to be done with caution, because all your company poms will inherit from it, so this pom have to be mature and stable (releasing a version of parent pom should not affect to release all your company projects!)

repositories

distribution managment sections

common plugins configurations (like maven-compiler-plugin source and target versions)

organization, developers, etc

second kind of parent pom is a multimodule parent. I prefer your first solution - this is a default maven convention for multi module projects, very often represents VCS code structure

The intention is to be scalable to a large scale build so should be scalable to a large number of projects and artifacts.

Mutliprojects have structure of trees - so you aren't arrown down to one level of parent pom. Try to find a suitable project struture for your needs - a classic exmample is how to disrtibute mutimodule projects

distibution/
documentation/
myproject/
  myproject-core/
  myproject-api/
  myproject-app/
  pom.xml
pom.xml

A few bonus questions: Where is the best place to define the various shared configuration as in source control, deployment directories, common plugins etc. (I'm assuming the parent but I've often been bitten by this and they've ended up in each project rather than a common one).

This configuration has to be wisely splitted into a "company" parent pom and project parent pom(s). Things related to all you project go to "company" parent and this related to current project go to project one's.

How do the maven-release plugin, hudson and nexus deal with how you set up your multi-projects (possibly a giant question, it's more if anyone has been caught out when by how a multi-project build has been set up)?

Company parent pom have to be released first. For multiprojects standard rules applies. CI server need to know all to build the project correctly.


So that there are two types of parent projects/poms. One without declareation. This is the one that is used for Inheritance. And a parent project with declaration. This is the one that submodules don't inherit from, it is just to manage building of the hold project. Am I right ?
b
bmargulies

An independent parent is the best practice for sharing configuration and options across otherwise uncoupled components. Apache has a parent pom project to share legal notices and some common packaging options. If your top-level project has real work in it, such as aggregating javadoc or packaging a release, then you will have conflicts between the settings needed to do that work and the settings you want to share out via parent. A parent-only project avoids that. A common pattern (ignoring #1 for the moment) is have the projects-with-code use a parent project as their parent, and have it use the top-level as a parent. This allows core things to be shared by all, but avoids the problem described in #2. The site plugin will get very confused if the parent structure is not the same as the directory structure. If you want to build an aggregate site, you'll need to do some fiddling to get around this. Apache CXF is an example the pattern in #2.


I've had a look at ibilio and lot of projects appear to prefer the "independent" parent pom. Hibernate, ActiveMQ, Jetty, XStream etc. Which suggests it is the defacto mechanism.
Another downside of the independent parent appears to be that the maven release plugin appears to want the parent to be pinned to a version before it will do a release. Probably not much of a problem since the parent shouldn't change too much.
I
Ivan Dubrov

There is one little catch with the third approach. Since aggregate POMs (myproject/pom.xml) usually don't have parent at all, they do not share configuration. That means all those aggregate POMs will have only default repositories.

That is not a problem if you only use plugins from Central, however, this will fail if you run plugin using the plugin:goal format from your internal repository. For example, you can have foo-maven-plugin with the groupId of org.example providing goal generate-foo. If you try to run it from the project root using command like mvn org.example:foo-maven-plugin:generate-foo, it will fail to run on the aggregate modules (see compatibility note).

Several solutions are possible:

Deploy plugin to the Maven Central (not always possible). Specify repository section in all of your aggregate POMs (breaks DRY principle). Have this internal repository configured in the settings.xml (either in local settings at ~/.m2/settings.xml or in the global settings at /conf/settings.xml). Will make build fail without those settings.xml (could be OK for large in-house projects that are never supposed to be built outside of the company). Use the parent with repositories settings in your aggregate POMs (could be too many parent POMs?).