Search code examples
javamavenmaven-module

Differences between a multi-module project and a parent project


In multi-module project in Maven, we have a parent pom with modules defined in <modules> tag, and in each module, we define which the parent pom is.

  • Why this two-way definition?

  • Why not define the relationship between them just in the parent part of the modules

  • How am I supposed to reuse modules if they are always bound to one parent?


Solution

  • Why this two-way definition?

    It is not mandatory. It is a design choice.

    Why not define just in the parent?

    If you define them only in the modules tag of the parent pom, you will only use the reactor/aggregation feature of Maven.

    1) Aggregation (<modules> declaration in the super aggregator project) provides mainly these features:

    • Collects all the available modules to build
    • Sorts the projects into the correct build order
    • Builds the selected projects in order

    Aggregation module is enabled by declaring the modules to aggregate in the parent pom:

    <modules>
        <module>my-child</module>
        <module>my-other-child</module>
    </modules>
    

    But aggregation doesn't provide inheritance.

    2) Project inheritance (<parent> declaration in the child modules) provides the inheritance of multiple things from the parent declaration to the child module :

    From the actual documentation, most elements from the parent POM are inherited by its children:

    • groupId
    • version
    • description
    • url
    • inceptionYear
    • organization
    • licenses
    • developers
    • contributors
    • mailingLists
    • scm
    • issueManagement
    • ciManagement
    • properties
    • dependencyManagement
    • dependencies
    • repositories
    • pluginRepositories
    • build
    • plugin executions with matching ids
    • plugin configuration
    • reporting
    • profiles

    Inheritance is enabled by declaring the parent artifact in the child poms:

    <parent>
        <groupId>my-group</groupId>
        <artifactId>my-parent</artifactId>
        <version>1.0.0</version>
    </parent>
    
    <!-- You can note that groupId and version are not filled for the current project.
     These are optional as inherited from the parent -->
    <artifactId>my-artifact</artifactId>
    

    In fact, you can use project inheritance, project composition, none of them or both.

    It is really a design choice that should be done according to the relation between the projects and their requirements.

    You may refer to this interesting point on the Maven documentation about these two features:

    Project Inheritance vs Project Aggregation

    If you have several Maven projects, and they all have similar configurations, you can refactor your projects by pulling out those similar configurations and making a parent project. Thus, all you have to do is to let your Maven projects inherit that parent project, and those configurations would then be applied to all of them.

    And if you have a group of projects that are built or processed together, you can create a parent project and have that parent project declare those projects as its modules. By doing so, you'd only have to build the parent and the rest will follow.

    But of course, you can have both Project Inheritance and Project Aggregation. Meaning, you can have your modules specify a parent project, and at the same time, have that parent project specify those Maven projects as its modules.

    To illustrate using an example.

    Here is a multi-module project's parent pom.xml.

    <!-- PARENT POM -->
    <groupId>com.example</groupId>
    <artifactId>parent-demo</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>pom</packaging>
    
    <modules>
        <module>child-module</module>
    </modules>
    

    And here is the Child Pom.

    <!-- CHILD POM -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>parent-demo</artifactId>
        <version>1.0.0-SNAPSHOT</version>
    </parent>
    <artifactId>chile-module</artifactId>
    

    Here, child-module inherits parent-demo, but parent-demo does not use any inheritance.

    And if you want, your parent-demo to also use inheritance, you can configure your parent-demo like below.

    <!-- PARENT POM -->
    <parent>
        <groupId>com.example</groupId>
        <artifactId>parent-deps</artifactId>
        <version>1.0.0-SNAPSHOT</version>
        <relativePath>../parent-deps</relativePath>
    </parent>
    <artifactId>parent-demo</artifactId>
    <packaging>pom</packaging>
    
    <modules>
        <module>child-module</module>
    </modules>
    

    And now, your parent-demo is also inheriting configurations from parent-deps which are cascaded down to child-module as well (unless ofcourse parent-demo decides to override them).