简体   繁体   中英

How to inherit from a multimodule Maven project with all its goodies?

The problem to which I cannot find a nice, scalable solution:

I have a project that delivers multiple flavours of the given artifact. This has been set up as a multimodule project, currently with 3 modules:

  • /flavour1_module
  • /flavour2_module
  • /flavour3_module

The thing is that I have another 50 projects that need to be setup in the same way, ie delivering the 3 flavours.

Solutions considered:

  1. turning the already created multimodule project into a parent for all other 50 projects
    • Cons: It just doesn't work. The instructions kept withing parent's modules are not inherited, thus they are not executed.
  2. using maven-archetype-plugin to create a multi-module project template , and then creating all 50 projects based on the template
    • Cons: if I would need flavour4, I need to manually update all 50 projects to add flavour4_module (and duplicate its content). Not scalable.
  3. embedding the configuration of all flavours into a single pom and enable or disable them based on profiles (ie using composition by profiles instead of inheritance via modules). Then pointing the 50 projects to it, as their parent. This would create "inline" modules
    • Cons: I would need to implement on my own mechanisms which are provided by modules out of the box. (eg building every flavour in a separate directory). I would also lose the clear seperation that modules provide.

Any ideas how to do it nicely? Is there any other option?

Thanks, Lukasz

Edit:

Another option would be extending the maven-reactor-plugin with reactor:inject-modules goal, which would download module definition from an external artifact, and attach its definition as a normal module. This would create a new module on the fly. Then all 50 projects could make this pom.xml their parent.

The configuration would look like this (a draft):

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-reactor-plugin</artifactId>
  <version>1.0</version>
  <executions>
    <execution>
      <id>inject</id>
      <phase>initialize</phase>
      <goals>
        <goal>inject-modules</goal>
      </goals>
      <configuration>
        <modules>
          <module>
            <artifactId>flavour1_module</artifactId>
            <groupId>[ groupId ]</groupId>
            <version>[ version ]</version>
          </module>
          <module>
            <artifactId>flavour2_module</artifactId>
            <groupId>[ groupId ]</groupId>
            <version>[ version ]</version>
          </module>
          <module>
            <artifactId>flavour3_module</artifactId>
            <groupId>[ groupId ]</groupId>
            <version>[ version ]</version>
          </module>
        </modules>
      </configuration>
    </execution>
  </executions>
</plugin>

Would going this way make sense?

Update:

Writing a plugin that manipulates the list of modules to execute (the idea of module injection that I described above) doesn't seem to be possible to implement, because modules are processed by maven core, and the mechanism was not designed to be extended with a plugin. This is confirmed by the fact that both plugins that do a similar job ie manipulating the list of projects to execute:

do the trick by executing a system call to create maven child process. For me it is not the way to go, because it's a very unstable solution. Indeed maven-reactor-plugin became incompatible with Maven3.

maven-invoker-plugin still looks promising. The plugin was originally designed to run integration tests, but it would be possible to use it to extend eg the compilation phase. But it requires the child pom.xml-s to be treated as resources and modified on the fly. For the problem that I described here the solution would be too complicated and unstable. I would prefer something lighter that could operate in memory while building maven model.

So for now I use profiles, trying to make them as compact as possible. Probably in a while I will need again to think about the problem.

Now you can use the maven-tiles plugin to get the desired behaviour.

With maven-tiles you can define build behaviours in different poms and import them wherever you like.

There's a working sample attached to MNG-5102 --> daddy3.zip

Maven's inheritance-only strait jacket is now officially removed.

In my opinion, you could create multiple different assembly descriptors for this and configure multiple plugin executions with each execution referring to different descriptor. You will have to maintain your project as a single module instead of multi module project. Provided your distributions contain same set of classes but different resources or libraries, it could work.

        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-assembly-plugin</artifactId>
            <version>2.2.1</version>
            <executions>
                <execution>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <id>assembly</id>
                    <phase>package</phase>
                    <configuration>
                        <descriptors>
                                <descriptor>one.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
                <execution>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <id>assembly</id>
                    <phase>package</phase>
                    <configuration>
                        <descriptors>
                                <descriptor>two.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
                <execution>
                    <goals>
                        <goal>single</goal>
                    </goals>
                    <id>assembly</id>
                    <phase>package</phase>
                    <configuration>
                        <descriptors>
                                                      <descriptor>three.xml</descriptor>
                        </descriptors>
                    </configuration>
                </execution>
            </executions>
        </plugin>

You could create a parent pom with assembly pluing configured there so that you can control the number of distributions and the change in packaging from there. Your projects will not need to know about details of different packaging.

I will strongly recommend to keep native libraries as separate module and use repository mechanism to install the compiled libraries into it. You can use different classifiers to segregate the platforms like,

mylib-2.0.0-win32_x86.dll
mylib-2.0.0-linux_x86.so
mylib-2.0.0-linux_x86_64.so

You can then reference to these libraries as dependencies in your project and then be able to package them along with your distribution.

The overall solution will greatly depend on how various distributions will differ and the overall process of packaging the distribution but I think this will work.

The ultimate and more scalable solution is to create your own packaging by implementing a Maven Plugin.

In my experience option 3 has worked the best, but I haven't had to scale it like you need to- when I've had to do that I've used the maven-ant-plugin to create a parameterized ant script to do the customization. It has some downsides- namely working with both ant and maven so the actual POM is more difficult to comprehend but it does allow for more flexibility than is otherwise possible with maven.

If you are using maven 3, you can define profiles the parent pom and activate them base on file existance. On the child modules you can "inherit flavours" by simply creating empty files.

This is better documented on the links below:

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM