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

3

14

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.

Toilet answered 12/1, 2016 at 3:19 Comment(2)
Related to this issue: issues.apache.org/jira/browse/ARCHETYPE-274Toilet
Also see issues.apache.org/jira/browse/ARCHETYPE-494.Predate
S
5

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>
Silverts answered 26/1, 2016 at 16:30 Comment(0)
P
3

I have forked the project and added a feature to enable or disable the generation of submodules based on properties passed to the Maven session.

See https://github.com/manouti/maven-archetype.

By setting -DgenerateEnableProperties=true when calling the create-from-project goal, the plugin would create enabler properties for each child module in the form generate.module.X. When calling the generate goal thereafter, one can exclude a module by passing -Dgenerate.module.X=false.

Alternatively:

You may be able to workaround this using partial archetypes by setting partial="true" in the descriptor, which allows the generation of a project on top of an existing project. This post seems to tackle the same issue.

Then you can write a script that takes the desired properties and generates the corresponding parts of the project using the partial archetypes, e.g. using Ant:

<target name="mvn.generate.project.module1" if="generate.module1">
    <exec dir="." executable="sh">
        <arg value="-c" />
        <arg value="mvn archetype:generate -DarchetypeGroupId="com.example.project" -DarchetypeArtifactId="archetype1" ..." />
    </exec>
</target>

<target name="mvn.generate.project.module2" if="generate.module2">
    <exec dir="." executable="sh">
        <arg value="-c" />
        <arg value="mvn archetype:generate -DarchetypeGroupId="com.example.project" -DarchetypeArtifactId="archetype2" ..." />
    </exec>
</target>

Update (6/11/16):

A related issue is https://issues.apache.org/jira/browse/ARCHETYPE-494. From the description of the committer:

There you can specify a groovy file, which will be executed after the archetype generation. I personally use this groovy file to do something similar: I read properties from the command line and then remove declared dependencies, classes and jsp files which the user might not need.

Predate answered 24/1, 2016 at 11:57 Comment(0)
N
0

I think what you are asking is in the context of this issue:

https://issues.apache.org/jira/browse/ARCHETYPE-494

I have it already implemented and will be included in the next version of the maven archetype plugin. There you can specify a groovy file, which will be executed after the archetype generation. I personally use this groovy file to do something similar: I read properties from the command line and then remove declared dependencies, classes and jsp files which the user might not need.

Please let me know if that helps.

Nev answered 9/6, 2016 at 9:51 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.