Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can a multi-module maven archetype be set up to have optional modules ?

I am going to create a multi-module archetype. It will generate several modules. Some users of the archetype may need all of them, while some only need some of them.

Can my archetype take arguments from the command line and decide which modules to generate? I checked https://maven.apache.org/archetype/archetype-models/archetype-descriptor/archetype-descriptor.html and it doesn't seem to support that.

like image 446
Jian Chen Avatar asked Jan 12 '16 03:01

Jian Chen


People also ask

What are the advantages of multi-module Maven project?

Why Multi-Module Project? One single command is required to build all projects, including the submodules. Maven always cares about the build order for you. You don't need to worry about that.

What is a multi-module Maven project?

A multi-module project is built from an aggregator POM that manages a group of submodules. In most cases, the aggregator is located in the project's root directory and must have packaging of type pom. The submodules are regular Maven projects, and they can be built separately or through the aggregator POM.

What is archetype selection in Maven?

In short, Archetype is a Maven project templating toolkit. An archetype is defined as an original pattern or model from which all other things of the same kind are made. The name fits as we are trying to provide a system that provides a consistent means of generating Maven projects.

What archetype should I choose for Maven project?

Some of the common Maven archetypes are as follows: maven-archetype-quickstart – Can be used to create a basic Maven project. maven-archetype-j2ee-simple – Can be used to create a simple j2ee project. maven-archetype-webapp – Can be used to create a web application.


1 Answers

In this specific case, the archetype could always create all the required modules and move the different flavors (set of modules) into profiles. Only one profile will be active by default as specified during the archetype:generate step.

As such, if I want to have the set of modules for flavorA, I will run the archetype as

mvn archetype:generate -DarchetypeGroupId=.. -DflavorA=true

And the archetype will pass this variable to the activeByDefault element of the flavorA profile re-defining the modules element for the set of modules required by the flavorA users.

The same could be done for flavorB and flavorB (for example), each defining a different set of modules.

An example of such an aggregator/parent POM as part of the archetype would be:

<profiles>
    <profile>
        <id>flavourA</id>
        <activation>
            <activeByDefault>${flavourA}</activeByDefault>
        </activation>
        <modules>
            <module>profiled-module2</module>
            <module>profiled-module3</module>
        </modules>
    </profile>
    <profile>
        <id>flavourB</id>
        <activation>
            <activeByDefault>${flavourB}</activeByDefault>
        </activation>
        <modules>
            <module>profiled-module3</module>
        </modules>
    </profile>
    <profile>
        <id>flavourC</id>
        <activation>
            <activeByDefault>${flavourC}</activeByDefault>
        </activation>
        <modules>
            <module>profiles-module1</module>
            <module>profiled-module2</module>
            <module>profiled-module3</module>
        </modules>
    </profile>
</profiles>

The archetype-metadata.xml file could then specify:

<requiredProperties>
    <requiredProperty key="flavourA">
        <defaultValue>false</defaultValue>
    </requiredProperty>
    <requiredProperty key="flavourB">
        <defaultValue>false</defaultValue>
    </requiredProperty>
    <requiredProperty key="flavourC">
        <defaultValue>false</defaultValue>
    </requiredProperty>
</requiredProperties>

And the archetype invoked with the -DflavorB=true option would then generate a pom as following:

<profiles>
    <profile>
        <id>flavourA</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <modules>
            <module>profiled-module2</module>
            <module>profiled-module3</module>
        </modules>
    </profile>
    <profile>
        <id>flavourB</id>
        <activation>
            <activeByDefault>true</activeByDefault>
        </activation>
        <modules>
            <module>profiled-module3</module>
        </modules>
    </profile>
    <profile>
        <id>flavourC</id>
        <activation>
            <activeByDefault>false</activeByDefault>
        </activation>
        <modules>
            <module>profiles-module1</module>
            <module>profiled-module2</module>
            <module>profiled-module3</module>
        </modules>
    </profile>
</profiles>

Such an approach has the following advantages and disadvantages:

Advantages

  • You keep the common modules and the archetype maintenance in one centralized place, while leaving the choice of flavors to the user of the archetype
  • Users of the archetype could, if desired and with zero-cost, switch from one flavor to another just activating/deactivating profiles
  • The approach uses standard Maven features

Disadvantages

  • Each archetype will generate the whole set of modules, even though not all of them will be required
  • If really a "noise", the user could manually delete the undesired modules, but still it would be a manual action

Moreover, on top of the approach above, we could also configure the Maven Clean Plugin in each profile to delete the modules not concerned by its flavor, so that at its first build (a maven clean), any non required module would be deleted. Such an approach would leave the POM with inconsistent profiles though, but it might be considered as well (not recommended).

Something like:

<profile>
    <id>flavourA</id>
    <activation>
        <activeByDefault>${flavorA}</activeByDefault>
    </activation>
    <modules>
        <module>profiled-module2</module>
        <module>profiled-module3</module>
    </modules>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-clean-plugin</artifactId>
                <version>3.0.0</version>
                <configuration>
                    <filesets>
                        <fileset>
                            <directory>${basedir}/profiled-module1</directory>
                        </fileset>
                    </filesets>
                </configuration>
            </plugin>
        </plugins>
    </build>
</profile>
like image 163
A_Di-Matteo Avatar answered Sep 18 '22 12:09

A_Di-Matteo