Sanity4J Maven plugin user guide

Intoduction

Sanity4J has been created in order to simplify running ad-hoc static code analysis over Java projects using a standardised set of rules types and priorities.

Various tools are used to conduct the analysis, each with their own set of requirements. Both bytecode and source code are analysed, to ensure the best chance of finding potential problems. Sanity4J presents a single interface to run all the tools and produce a combined report presenting all the findings in a easily accessible manner.

Integrating Sanity4J into your Maven project.

To run the Maven Plugin, you will need the following:

  • The Sanity4J jar & POM.
  • Maven 3+
  • JDK/JRE 1.8.x+
  • A directory containing the tools needed by Sanity4J (see parameters below). *
  • A Maven project, optionally with a JaCoCo plugin already included.
  • Depending on the size of your project, you may need to increase the memory available to Maven. This can be set using the MAVEN_OPTS environment variable, e.g. "set MAVEN_OPTS=-Xmx512M" to use 512MB max heap.

Parameters

ParameterDescriptionRequired
productsDirThe 3rd party product tools are configured by default to use the Maven transitive dependencies of the tools defined for use. The default tools can be overridden with a sanity4j.properties file. Alternatively, the productsDir can be set to point to a directory containing all the tools in use. For example, with a default configuration, these could be spotbugs-3.1.6, pmd-5.0.4, checkstyle-5.6 and jacoco-0.7.9.No
reportDirThe report output directory. This parameter defaults to the project's site directory.No
coverageDataFileThe location of a coverage data file (e.g. jacoco.exec for JaCoCo) if you want to include unit testing coverage data in your report. If this parameter is omitted, it is assumed that the default JaCoCo data file will be used.No
aggregateIf this Maven project is a multi module parent, then setting aggregate to true will enable merging of coverage data files.No
coverageMergeDataFileThe location of the merged coverage data file. Only used when aggregate is true. If this parameter is omitted, then cobertura-merged.ser will be used.No
externalPropertiesPathThe path location of the sanity4j.properties file. The default is the current directory.No
additionalPropertiesAny additional properties passed to the tools. These should be in the same format as a normal properties file, ie with name = value pairs.No
checkStyleConfigThe configuration passed to the Checkstyle $sanity4j.tool.checkstyle.command as $sanity4j.tool.checkstyle.config. The resource can be a file contained within a jar file on the classpath, or an external file in the file system. If the resource is a jar, then the name is compared with the classpath and the full path to the jar is then passed to the tool instead.No
spotBugsConfigThe configuration passed to the SpotBugs $sanity4j.tool.spotbugs.command as $sanity4j.tool.spotbugs.config. The resource can be a file contained within a jar file on the classpath, or an external file in the file system. If the resource is a jar, then the name is compared with the classpath and the full path to the jar is then passed to the tool instead.No
pmdConfigThe configuration passed to the PMD $sanity4j.tool.pmd.command as $sanity4j.tool.pmd.config. The resource can be a file contained within a jar file on the classpath, or an external file in the file system. If the resource is a jar, then the name is compared with the classpath and the full path to the jar is then passed to the tool instead.No
javaRuntimeThe full path to the java run-time to use. If not specified, "java" is used.No
javaArgsThe java arguments to use such as the Max Heap size. If not specified, the current existing MAVEN_OPTS environment variable is passed through.No
summaryDataFileThe location of a (persistent) summary data file if you want to include trend graphs over time.No
includeToolOutputIf set to "true", the raw tool xml output is also copied into the report directory. This is only useful if there is some other part of your build process that requires it.No
sourcesThis element accepts nested Paths pointing to the relative location of the target project's source. If you have multiple source directories contained within a main directory, you can just list the main directory here - the task will search for all source directories. The default is to use the project's "src/main" directory.No
testSourcesThis element accepts nested Paths pointing to the relative location of the target project's test source. If you have multiple source directories contained within a test directory, you can just list the test directory here - the task will search for all source directories. The default is to use the project's "src/test" directory.No
classesThis element accepts nested paths pointing to the location of the target project's built classes only. The default is to use the project's "target/classes" directory.No
testClassesThis element accepts nested paths pointing to the location of the target project's built test classes. The default is to use the project's "target/test-classes" directory.No
librariesThis element accepts nested Paths / FileSets pointing to the location of jars/classes that the target project depends on. Don't use e.g. an entire local maven repository; only include direct dependencies. The default is to use the project's current set of transitive dependencies.No
useHistoryAllows retrieval of the QA statistics history CSV file from the current deployed site. For this to work the Distribution Management must be defined within your project's POM file for the location of the Site. The default is true.No

The source / class / library paths will accept multiple path entries. If there are multiple source / class directories, it is possible to specify a common parent directory and have the tool find all the nested source/class directories.

The productsDir can point to a directory containing all the tools in use. For example, with a default configuration, these could be spotbugs-3.1.6, pmd-5.0.4, checkstyle-5.6 and jacoco-0.7.9.

Below is a simple example XML to integrate Sanity4J into your project's POM.

  <reporting>
    <plugins>
      ...
      <plugin>
        <groupId>com.github.sanity4j</groupId>
        <artifactId>sanity4j</artifactId>
        <version>1.8.2</version>
      </plugin>
      ...
    </plugins>
  </reporting>

Below is another example for Maven 3 where the config is passed in to the tools along with additional properties.

  <reporting>
    <plugins>

      <plugin>
        <groupId>com.github.sanity4j</groupId>
        <artifactId>sanity4j</artifactId>
        <version>1.8.2</version>
        <configuration>
          <spotBugsConfig>-exclude $${sanity4j_filter_exclude.xml}</spotBugsConfig>
          <pmdConfig>$${sanity4j_pmd_rules.xml}</pmdConfig>
          <checkStyleConfig>$${sanity4j_checks.xml}</checkStyleConfig>

          <additionalProperties>
            PMD.DoNotUseThreads.excludes       =.*
            PMD.UseProperClassLoader.excludes  =.*
          </additionalProperties>
        </configuration>
      </plugin>

    </plugins>
  </reporting>

Sanity4J supports Maven dependencies for configuring 3rd party product tools such as spotbugs, pmd, checkstyle etc. As each tool may have different versions of the same dependency, the transitive dependencies of each tool are used individually. The default tools are specified in the in sanity4j.properties file. However, these can be overridden if you require the use of custom plugin rules.

Below is a more advanced example Maven 3 configuration for Sanity4J where the use of custom tool plugins are defined.

  <build>
    <plugins>
      <plugin>
        <groupId>com.github.sanity4j</groupId>
        <artifactId>sanity4j</artifactId>
        <version>1.8.2</version>
        <dependencies>
          <dependency>
            <!--
              This adds your custom rules to the classpath of sanity4j.
              Inside this artifact you can place a sanity4j.properties
              file which then defines dependencies on the custom tool
              plugins to use.
            -->
            <groupId>my_company</groupId>
            <artifactId>custom_qa_rules</artifactId>
            <version>1.0.0</version>
          </dependency>
        </dependencies>
      </plugin>
    </plugins>
  </build>

  <reporting>
    <plugins>

      <plugin>
        <groupId>com.github.sanity4j</groupId>
        <artifactId>sanity4j</artifactId>
        <version>1.8.2</version>
        <configuration>
          <aggregate>true</aggregate>

          <!--
            This is a resource on the classpath.
            It's contained within the custom_qa_rules JAR file and specified as a dependency to the plugin.
           -->
          <externalPropertiesPath>sanity4j.properties</externalPropertiesPath>
        </configuration>
      </plugin>

    </plugins>
  </reporting>

Then, within the sanity4j.properties file of your custom_qa_rules JAR, you can define the overrides of the transitive dependencies of the tools to use with the plugins. Each of your custom rule artifacts must define a dependency on the tool with which they will be used. This provides the hook into sanity4j as it will use the transitive dependencies to derive the classpath for the tool.

# custom_qa_checkstyle44_rules defines a dependency on checkstyle:checkstyle:4.4:jar
sanity4j.tool.checkstyle.versions          =4.4
sanity4j.tool.checkstyle.4.4.maven         =my_company:custom_qa_checkstyle44_rules:1.0.0:jar
sanity4j.tool.checkstyle.4.4.config        =custom_checkstyle4-4_rules.xml

sanity4j.tool.jacoco.versions              =0.7.9
sanity4j.tool.jacoco.0.7.9.maven           =org.jacoco:jacoco-maven-plugin:0.7.9:jar

sanity4j.tool.jacoco-merge.versions        =0.7.9
sanity4j.tool.jacoco-merge.0.7.9.maven     =org.jacoco:jacoco-maven-plugin:0.7.9:jar

# custom_qa_spotbugs316_rules needs to be bundled inside the custom_qa_rules artifact so that it
# can be passed as a config parameter to spotbugs.
sanity4j.tool.spotbugs.versions            =1.3.9
sanity4j.tool.spotbugs.3.1.6.maven         =com.google.code.spotbugs:spotbugs:3.1.6:jar
sanity4j.tool.spotbugs.3.1.6.config        =-pluginList ${custom_qa_spotbugs316_rules.jar}${path.separator}${more_custom_qa_spotbugs316_rules.jar}

# custom_qa_pmd4_rules defines a dependency on pmd:pmd:4.3:jar
# custom_qa_pmd4_rules needs to be bundled inside the custom_qa_rules artifact so that it
# can be passed as a config parameter to pmd.
sanity4j.tool.pmd.versions                 =4.3.0
sanity4j.tool.pmd.4.3.0.maven              =my_company:custom_qa_pmd4_rules:1.0.0:jar
sanity4j.tool.pmd.4.3.0.config             =jar:file:///${custom_qa_pmd4_rules.jar}!/custom_pmd_rules.xml

# custom_qa_pmd4_rules defines a dependency on pmd:pmd:4.3:jar
sanity4j.tool.pmd-cpd.versions             =4.3.0
sanity4j.tool.pmd-cpd.4.3.0.maven          =my_company:custom_qa_pmd4_rules:1.0.0:jar

Another option for retrieving the tools from Maven is to use the maven-dependency-plugin. The maven-dependency-plugin can be used to copy the tool JARs to a known location, then the productsDir parameter can be used to specify that location.

    <build>
        <plugins>

            <!-- Copy the tools from a maven repository instead of using them from the local file system. -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.8</version>
                <executions>
                    <execution>
                        <id>sanity4j-tools-checkstyle</id>
                        <phase>pre-site</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/tools/checkstyle-5.6</outputDirectory>

                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.puppycrawl.tools</groupId>
                                    <artifactId>checkstyle</artifactId>
                                    <version>5.6</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>antlr</groupId>
                                    <artifactId>antlr</artifactId>
                                    <version>2.7.7</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>commons-beanutils</groupId>
                                    <artifactId>commons-beanutils-core</artifactId>
                                    <version>1.8.3</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>commons-cli</groupId>
                                    <artifactId>commons-cli</artifactId>
                                    <version>1.2</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>com.google.collections</groupId>
                                    <artifactId>google-collections</artifactId>
                                    <version>1.0</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>commons-logging</groupId>
                                    <artifactId>commons-logging</artifactId>
                                    <version>1.0.4</version>
                                </artifactItem>
                            </artifactItems>

                        </configuration>
                    </execution>
                    <execution>
                        <id>sanity4j-tools-jacoco</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/tools/jacoco-0.7.9</outputDirectory>

                            <artifactItems>
                                                                <artifactItem>
                                                                        <groupId>org.jacoco</groupId>
                                                                        <artifactId>org.jacoco.core</artifactId>
                                                                        <version>0.7.9</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-debug-all</artifactId>
                                                                        <version>5.2</version>
                                                                </artifactItem>
                            </artifactItems>

                        </configuration>
                    </execution>
                    <execution>
                        <id>sanity4j-tools-spotbugs</id>
                        <phase>pre-site</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/tools/spotbugs-3.1.6</outputDirectory>

                            <artifactItems>
                                                                <artifactItem>
                                                                        <groupId>com.github.spotbugs</groupId>
                                                                        <artifactId>spotbugs</artifactId>
                                                                        <version>3.1.6</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm</artifactId>
                                                                        <version>6.2</version>
                                                        </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-analysis</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-commons</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-tree</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-util</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.ow2.asm</groupId>
                                                                        <artifactId>asm-xml</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.apache.bcel</groupId>
                                                                        <artifactId>bcel</artifactId>
                                                                        <version>6.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>commons-lang</groupId>
                                                                        <artifactId>commons-lang</artifactId>
                                                                        <version>2.6</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>org.dom4j</groupId>
                                                                        <artifactId>dom4j</artifactId>
                                                                        <version>2.1.0</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>jaxen</groupId>
                                                                        <artifactId>jaxen</artifactId>
                                                                        <version>1.1.6</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>net.jcip</groupId>
                                                                        <artifactId>jcip-annotations</artifactId>
                                                                        <version>1.0</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>com.google.code.findbugs</groupId>
                                                                        <artifactId>jFormatString</artifactId>
                                                                        <version>3.0.0</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>com.google.code.findbugs</groupId>
                                                                        <artifactId>jsr305</artifactId>
                                                                        <version>3.0.2</version>
                                                                </artifactItem>
                                                                <artifactItem>
                                                                        <groupId>com.github.spotbugs</groupId>
                                                                        <artifactId>spotbugs-annotations</artifactId>
                                                                        <version>3.1.6</version>
                                                                </artifactItem>
                                                        </artifactItems>

                        </configuration>
                    </execution>
                    <execution>
                        <id>sanity4j-tools-pmd</id>
                        <phase>pre-site</phase>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>${project.build.directory}/tools/pmd-5.0.4</outputDirectory>

                            <artifactItems>
                                <artifactItem>
                                    <groupId>net.sourceforge.pmd</groupId>
                                    <artifactId>pmd</artifactId>
                                    <version>5.0.4</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>jaxen</groupId>
                                    <artifactId>jaxen</artifactId>
                                    <version>1.1.1</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>com.beust</groupId>
                                    <artifactId>jcommander</artifactId>
                                    <version>1.27</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>asm</groupId>
                                    <artifactId>asm</artifactId>
                                    <version>3.2</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>net.sourceforge.saxon</groupId>
                                    <artifactId>saxon</artifactId>
                                    <version>9.1.0.8</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>net.sourceforge.saxon</groupId>
                                    <artifactId>saxon</artifactId>
                                    <version>9.1.0.8</version>
                                    <classifier>dom</classifier>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>org.mozilla</groupId>
                                    <artifactId>rhino</artifactId>
                                    <version>1.7R3</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>junit</groupId>
                                    <artifactId>junit</artifactId>
                                    <version>4.4</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>xerces</groupId>
                                    <artifactId>xercesImpl</artifactId>
                                    <version>2.9.1</version>
                                    <type>jar</type>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>net.java.dev.javacc</groupId>
                                    <artifactId>javacc</artifactId>
                                    <version>4.1</version>
                                </artifactItem>
                                <artifactItem>
                                    <groupId>commons-io</groupId>
                                    <artifactId>commons-io</artifactId>
                                    <version>2.2</version>
                                </artifactItem>
                            </artifactItems>

                        </configuration>
                    </execution>
                </executions>
            </plugin>

        </plugins>
    </build>

Then the productsDir is used to locate the directory where the tools were downloaded to.

    <plugin>
        <groupId>com.github.sanity4j</groupId>
        <artifactId>sanity4j</artifactId>
        <version>1.8.2</version>
        <configuration>
            <productsDir>${project.build.directory}/tools</productsDir>
        </configuration>
    </plugin>