7

I want to generate an effective pom for all the subprojects in a multi-module build.

The help:effective-pom documentation here states

It will iterate over all projects in the current build session, printing the effective POM for each

I'm running mvn help:effective-pom in the root directory of this maven project and it's only generating for the root and not for the subprojects.

Why isn't the effective pom being generated for all projects. Note: I have another real world maven project where mvn help:effective-pom is correctly generating a <projects> tag with nested <project> for each submodule. I am unsure why it is not working for this maven project

Here is the effective pom generated

<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Generated by Maven Help Plugin on 2017-11-12T09:56:26                  -->
<!-- See: http://maven.apache.org/plugins/maven-help-plugin/                -->
<!--                                                                        -->
<!-- ====================================================================== -->

<!-- ====================================================================== -->
<!--                                                                        -->
<!-- Effective POM for project                                              -->
<!-- 'org.gradle.test.performance:project:pom:1.0'                          -->
<!--                                                                        -->
<!-- ====================================================================== -->

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>org.gradle.test.performance</groupId>
  <artifactId>project</artifactId>
  <version>1.0</version>
  <packaging>pom</packaging>
  <modules>
    <module>project0</module>
    <module>project1</module>
    <module>project2</module>
    <module>project3</module>
    <module>project4</module>
    <module>project5</module>
    <module>project6</module>
    <module>project7</module>
    <module>project8</module>
    <module>project9</module>
  </modules>
  <repositories>
    <repository>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </repository>
  </repositories>
  <pluginRepositories>
    <pluginRepository>
      <releases>
        <updatePolicy>never</updatePolicy>
      </releases>
      <snapshots>
        <enabled>false</enabled>
      </snapshots>
      <id>central</id>
      <name>Central Repository</name>
      <url>https://repo.maven.apache.org/maven2</url>
    </pluginRepository>
  </pluginRepositories>
  <build>
    <sourceDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\src\main\java</sourceDirectory>
    <scriptSourceDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\src\main\scripts</scriptSourceDirectory>
    <testSourceDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\src\test\java</testSourceDirectory>
    <outputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\classes</outputDirectory>
    <testOutputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\test-classes</testOutputDirectory>
    <resources>
      <resource>
        <directory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\src\main\resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\src\test\resources</directory>
      </testResource>
    </testResources>
    <directory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target</directory>
    <finalName>project-1.0</finalName>
    <pluginManagement>
      <plugins>
        <plugin>
          <artifactId>maven-antrun-plugin</artifactId>
          <version>1.3</version>
        </plugin>
        <plugin>
          <artifactId>maven-assembly-plugin</artifactId>
          <version>2.2-beta-5</version>
        </plugin>
        <plugin>
          <artifactId>maven-dependency-plugin</artifactId>
          <version>2.8</version>
        </plugin>
        <plugin>
          <artifactId>maven-release-plugin</artifactId>
          <version>2.3.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
    <plugins>
      <plugin>
        <artifactId>maven-clean-plugin</artifactId>
        <version>2.5</version>
        <executions>
          <execution>
            <id>default-clean</id>
            <phase>clean</phase>
            <goals>
              <goal>clean</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-install-plugin</artifactId>
        <version>2.4</version>
        <executions>
          <execution>
            <id>default-install</id>
            <phase>install</phase>
            <goals>
              <goal>install</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-deploy-plugin</artifactId>
        <version>2.7</version>
        <executions>
          <execution>
            <id>default-deploy</id>
            <phase>deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
          </execution>
        </executions>
      </plugin>
      <plugin>
        <artifactId>maven-site-plugin</artifactId>
        <version>3.3</version>
        <executions>
          <execution>
            <id>default-site</id>
            <phase>site</phase>
            <goals>
              <goal>site</goal>
            </goals>
            <configuration>
              <outputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
          <execution>
            <id>default-deploy</id>
            <phase>site-deploy</phase>
            <goals>
              <goal>deploy</goal>
            </goals>
            <configuration>
              <outputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\site</outputDirectory>
              <reportPlugins>
                <reportPlugin>
                  <groupId>org.apache.maven.plugins</groupId>
                  <artifactId>maven-project-info-reports-plugin</artifactId>
                </reportPlugin>
              </reportPlugins>
            </configuration>
          </execution>
        </executions>
        <configuration>
          <outputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\site</outputDirectory>
          <reportPlugins>
            <reportPlugin>
              <groupId>org.apache.maven.plugins</groupId>
              <artifactId>maven-project-info-reports-plugin</artifactId>
            </reportPlugin>
          </reportPlugins>
        </configuration>
      </plugin>
    </plugins>
  </build>
  <reporting>
    <outputDirectory>C:\code\gradle-maven-transform\example\smallJavaMultiProject\target\site</outputDirectory>
  </reporting>
</project>
lance-java
  • 25,497
  • 4
  • 59
  • 101

3 Answers3

4

The EffectivePomMojo is an aggregator goal. Which means it's invoked only for the module that you run it for. But you're right that it should dump all the sub-projects as well. The reason it doesn't do this in your case is because of this line:

if ( projects.get( 0 ).equals( project ) && projects.size() > 1 )

In your case the upper-most project is last in the graph (because there are no dependencies on it from any other module). If you add it as a parent to project0 (and only for that module), then it'd put your root pom at the 1st position in the graph and everything will work as you expect.

I can't come up with a justification for this behaviour. So if you raise an issue in the bugtracker everyone will benefit :) Please update us if/when you get the answer.

PS: such questions are easy to solve if you know how to debug Maven plugins. For this you can use mvnDebug instead of mvn and then open plugin's source code and attach to the debug session.

Stanislav Bashkyrtsev
  • 14,470
  • 7
  • 42
  • 45
  • Thanks for your input but unfortunately a bug fix doesn't help as it would require users of my utility to upgrade maven which I definitely don't want. I need something that "just works". – lance-java Nov 13 '17 at 21:23
  • You don't actually need to upgrade Maven. Instead of the shortcut you can use the fully qualified plugin GAV which would use whichever version you specify: `org.apache.maven.plugins:maven-help-plugin:2.2:effective-pom` – Stanislav Bashkyrtsev Nov 13 '17 at 21:38
  • Interesting, I can do this from command line? Or need to put this in the `pom.xml` – lance-java Nov 13 '17 at 22:37
  • In command line. You need to have plugins in pom.xml only if you want to bind them to phases like test, compile, package or if you want to pre-configure them. – Stanislav Bashkyrtsev Nov 14 '17 at 06:05
  • @StanislavBashkyrtsev Any help for https://stackoverflow.com/questions/55530477/maven-pom-inheritance-ands-overriding-in-parent-child-module ? – Number945 Apr 05 '19 at 08:05
2

You need to specify the parent element in each of your sub-modules pom.xml in addition to the modules elements in your root project such as:

<parent>
    <groupId>org.gradle.test.performance</groupId>
    <artifactId>project</artifactId>
    <version>1.0</version>
</parent>

Otherwise it won't be picked-up when you run help:effective-pom command.

EDIT: some precision as to why the plugin does not work with Aggregation. Aggregation (done with modules element) is different than Inheritance (using the parent element). However the plugin documentation clearly mentions:

The effective-pom goal is used to make visible the POM that results from the application of interpolation, inheritance and active profiles.

And there is no mention of aggregated plugins. I believe it basically means:

I will take the pom you are providing me, apply interpolation, inheritance and active profiles but NOT aggregation, and give you the resulting pom. Deal with it.

Pierre B.
  • 11,612
  • 1
  • 37
  • 58
  • Thanks for the info, whilst this might make it work... there is no requirement in maven that sub modules in a multi-module build must inherit from a parent. The multi-module project builds perfectly fine in maven without inheritance. What would happen if some modules inherited from `parent1` and others inherited from `project2`? This is also a valid use case in maven? – lance-java Nov 13 '17 at 11:47
  • 1
    From the doc: `The effective-pom goal is used to make visible the POM that results from the application of interpolation, inheritance and active profiles.` It mentions Inheritance, but with modules you are using Aggregation - that's different, and I think this behavior is then expected by the Help Plugin ;) No, there is no requirement that aggregated modules such as yours also inherit from the same project. If some modules inherit from different parents but are aggregated together, that's a perfectly valid case, though it may not be regarded as best practice. – Pierre B. Nov 13 '17 at 17:26
  • I've worked on many projects where the "aggregator" is not the parent (there's a separate project for the parent). So guessing this scenario won't work either. I was looking for a generic solution to get the effective pom for the "aggregate" of projects (ie the collection which is built via `mvn package`). Unfortunately it seems that `mvn help:effective-pom` can't do this generically. Think I'll investigate ModelBuilder as discussed [here](https://stackoverflow.com/a/4881362/1089967). Thanks again – lance-java Nov 13 '17 at 18:01
1

I ended up with a different solution in the end. Rather than accepting a single root pom.xml as input, I instead require a collection of pom.xml to be resolved. I also now embed the maven-model-builder and invoke the DefaultModelBuilder via a DefaultModelBuildingRequest

Eg:

DefaultModelBuilderFactory factory = new DefaultModelBuilderFactory();
DefaultModelBuilder builder = factory.newInstance();
ModelBuildingRequest req = new DefaultModelBuildingRequest();
req.setProcessPlugins(false);
req.setModelResolver(createModelResolver());
req.setValidationLevel(ModelBuildingRequest.VALIDATION_LEVEL_MINIMAL);
for (File pomFile : pomFiles) {
   req.setPomFile(pomFile);
   Model effectivePom = builder.build(req).getEffectiveModel();
   ...
}

Code here for anyone interested

lance-java
  • 25,497
  • 4
  • 59
  • 101
  • 1
    This doesn't answer the question. It doesn't even relate to the question. – Stanislav Bashkyrtsev Nov 16 '17 at 17:55
  • Well... my ultimate goal is to have an effective pom for every pom.xml in a maven build. Since I've proven that `help:effective-pom` doesn't always do this from the root project my remaining choice was to call `help:effective-pom` for each `pom.xml`. I found a way of doing this without needing maven installed, via the maven APIs which is much quicker than invoking `mvn help:effective-pom` from the shell – lance-java Nov 16 '17 at 19:59
  • I would appreciate if you could include more details about the `createModelResolver()` method, I do not understand how to instantiate a `ModelResolver`. – Sebastian P. Dec 22 '21 at 13:01
  • 1
    See [this search](https://github.com/search?q=user%3Auklance+ModelResolverImpl&type=code) of my github repo – lance-java Dec 22 '21 at 13:58
  • While I have to agree with the others that this answer solves a different problem than what you have asked for in the question, it helped me so much with a problem that I was facing! Thanks! – Sebastian P. Dec 22 '21 at 23:55
  • My initial problem statement is "I want to generate an effective pom for all the subprojects in a multi-module build". This answer solves that problem – lance-java Dec 23 '21 at 09:51