Reporting on a Multi-Module Project with Maven2

Maarten Winkels

One of the things that changed considerably between Maven1 and Mvn2 is the way in which multi-module projects work. In Maven1 multi-module projects are implicit: A directory that contains subdirectories with project.xmls is a multi-module project. Using the multiproject plugin goals can be executed in all modules sequentially. In Mvn2 multi-module projects are explicit: The pom.xml must contain references to the sub projects. These references are relative links on the filesystem to directories where the subprojects pom.xmls can be found. A normal build will then invoke the build of the subprojects.

This is all very well documented on the Maven site and relatively easy to grasp, migrate and work with. What is not very easy or well documented is generating a decent site on a multi-module project. In this blog I will share my experiences on how this can be done with Mvn2.


Parent-Child, Container-Component

A project can have modules and a project can have a parent. Is this a bidirectional relationship? Can a project be the child of a project in which it is not a module? Semantically the relationships are quite different. A child project uses the metadata (pom.xml) of it's parent to derive its own metadata. A module container only declares that its build consists of the consecutive builds of its module components, it doesn't imply any relationship between the metadata of the components. This is quite convenient, since a multi-module project will likely contain components with very disimilar artifacts, like EARs and WARs or server and client side components.

Luckily Mvn2 supports this setup... just not for the site phase. Well, actually, the site is build correctly, but if the module container is also the parent of its components, the modules are shown on the main page of the container project, otherwise they are not. This check is done in the plugin code exactly as I describe it above. If the parent of a component is the same as the container, the project is shown as a module, otherwise it is discarded. I cannot really follow the logic in this and am tempted to think that this is a bug. Since for all practical uses it is fine to declare the module container as the parent of all module components, I don't really think it's an issue.

Aggregating reports

One of the most important features of Mvn2 (and Maven1), I think, is its reporting plugins. These plugins give a high level view of the project and its code quality. One of the problems with multi-module projects is that there are so many reports. Each module has its own coverage, dependency, test result and other reports, as well as its own browseable (test) sources. In Maven1, there was the dashboard plugin, that tried to aggregate all information in a single view. Unfortunately this crafty plugin is not (yet) available for Mvn2.

Some plugins can do aggregation like the JXR and Javadoc plugins. For most other reporting plugins I have only seen it on the long list of wanted features. The Clover plugin struggles hard to aggregate its reports, but it needs two consecutive site phases ('mvn site site') to do the aggregation. The clover plugin developers seem to hold the site plugin responsible because it doesn't handle @aggregator reporting plugins correctly. I cannot find any documentation on this annotation, there is nothing in the plugin developer guide. The main problems I see for aggregating reports is the fact that the parent report will be generated before the child reports have been generated. If report generation for the parent could be postponed untill after the builds of the children, most problems for the clover team as well as dashboard plugins would be history.

I think aggregating the JXR and Javadoc report is good. Mostly you'll have classes in your submodules that depend on classes in other modules. The JXR and Javadoc report will know where to find the associated reports if you aggregate. The report will thus be more complete. One problem with aggregating these reports is that other plugins depend on them. The Surefire, PMD and Checkstyle report create links to the JXR report where they see problems in the code. This is very convenient if you're trying to spot the problem. Luckily, these reports have a xrefLocation property that can be used to specify the relative path to the JXR reports. The default value for the xReflocation is ${project.reporting.outputDirectory}/xref, so to make it work with an aggregated report, chinging this to ${project.reporting.outputDirectory}/../xref should be sufficient. The aggregated reports will be at the default xref location of the parent project. Unfortunately, the Surefire and PMD reporting plugins have the same nasty bug: To calculate the XRef links, the xrefLocation property (which is a java.io.File) is compared with the outputDirectory property (which is a java.lang.String). If the xrefLocation is specified as ${project.reporting.outputDirectory}/../xref, it will be filled with a full OS-dependent file path. The outputDirectory property, which is by default set to ${project.reporting.outputDirectory}, will default to: 'target/site'. When comparing 'c:\projects\myproject\mysubproject\target\site\..\xref' to 'target/site' te determine the correct relative path, the maven plugins just give up, convinced that the paths have no relation at all, and fall back to the default. Even on a UNIX or Linux system '/home/cruisecontrol/checkout/myproject/mysubproject/target/site/../xref' is not relative to 'target/site'.

The simple solution is to change the type of the outputDirectory property to java.io.File. This will default to a file poinint to 'target/site' in the basedir, thus 'c:\projects\myproject\mysubproject\target\site'. Now comparing this to 'c:\projects\myproject\mysubproject\target\site\..\xref' will yield '..\xref' as desired. The fact that both plugins are so consistently buggy, stems from the abstract parent that both plugins use. The org.apache.maven.reporting.AbstractMavenReport declares an abstract method String getOutputDirectory(). This might even be worth a bug report, since the String is obviously meant to denote a file (or directory). Strong typing is a very usefull Java feature as well as OS independence.

Multi-project reporting in pom.xml

Now, how do you configure reporting in your multi-module pom.xml to generate a nice site?
The following settings work for me (after having applied patches to the PMD and Surefire plugins):

  
    
      
        maven-clover-plugin
        
          ${settings.localRepository}/path/to/license
        
        
          
            pre-site
            
              instrument
              aggregate
            
          
        
      
    
  
  
    
      
        maven-jxr-plugin
        
          true
        
      
      
        maven-javadoc-plugin
        
          true
        
      
      
        maven-surefire-report-plugin
        
          ${project.reporting.outputDirectory}/../xref-test
        
      
      
        maven-clover-plugin
      
      
        maven-pmd-plugin
        
          ${project.reporting.outputDirectory}/../xref
        
      
      
        maven-changes-plugin
      
      
        maven-checkstyle-plugin
        
          ${settings.localRepository}/path /to/checkstyle.config
          false
          ${project.reporting.outputDirectory}/../xref
        
      
      
      
        org.codehaus.mojo
        jdepend-maven-plugin
      
      
        org.codehaus.mojo
        findbugs-maven-plugin
      
      
        org.codehaus.mojo
        cobertura-maven-plugin
      
      
        org.codehaus.mojo
        javancss-maven-plugin
      
      
        org.codehaus.mojo
        taglist-maven-plugin
      
    
  

The site should be build as mvn site site to allow clover to aggregate the reports. All links from and Surfire, PMD, Checkstyle to the aggregated JXR report will be generated correctly. The findbugs plugin is an other matter: It uses a resource bundle to find the "xrefLocation"... We'll solve that one in another blog.

Comments (4)

  1. Immo Huneke - Reply

    March 22, 2007 at 4:27 pm

    It never occurred to me to invoke the same goal twice in a single mvn run. Brilliant. This opens up a whole range of new possibilities!

  2. Tim Bruijnzeels - Reply

    July 12, 2007 at 10:11 am

    Slightly related, or well not to reporting, but to running mvn goals on sub-projects.

    Updating your sub-projects from the parent doesn't work as you might expect: scm:update on the parent does NOT update the sub-projects. See here:

    http://jira.codehaus.org/browse/SCM-116

    this behavior is IMHO unexpected because the other goals do tend to descend into the sub-projects.

    Run this instead if you want to update the parent and the sub-projects as well:
    mvn scm:update-subprojects

  3. Corey - Reply

    September 27, 2007 at 5:37 pm

    Can you explain how to apply the patches to surefire and PMD?

    I believe the surefire patch you're referring to is http://jira.codehaus.org/browse/SUREFIRE-268 but how do you apply patches to the plugins?

  4. Matteo - Reply

    July 9, 2008 at 10:59 am

    I think this explanation is deprecated, because findbugs xrefLocation doesn't exists anymore. At least in 1.2 version.

Add a Comment