Maven y PMD

De ChuWiki


Integrar PMD y maven[editar]

PMD es una herramienta que permite pasar métricas a nuestro código java. Podemos integrar PMD en el ciclo de vida de nuestro proyecto Maven de forma que se pasen métricas cada vez que compilemos nuestro código.

maven-pmd-plugin[editar]

Teniendo instalado maven, sólo tenemos que añadir maven-pmd-plugin en nuestro fichero pom.xml

<project>
...
   <reporting>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-pmd-plugin</artifactId>
            <version>3.21.2</version>
         </plugin>
      </plugins>
   </reporting>
</project>

Una vez echo esto, ejecutando

mvn pmd:pmd

Nos analizará las métricas por defecto que pmd tiene instaladas y generará en target/site/pmd.html un report con todas las métricas que hemos "violado". Abriendo este pmd.xml con un navegador web, podemos ver algo como la siguiente imagen

Informe PMD generado por maven-pmd-plugin
Informe PMD generado por maven-pmd-plugin

Configurar reglas que se pasan con PMD[editar]

Podemos decidir nosotros qué métricas queremos que se pasen, poniéndolas en un fichero xml.

Pasar sólo reglas concretas[editar]

El siguiente fichero, por ejemplo, es un fichero de configuración para pmd que le indica que sólo mire la complejidad ciclomática.

<?xml version="1.0"?>
<ruleset name="Custom Rules"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
    <description>
        Custom Rules
    </description>

    <!-- Now we'll customize a rule's property value -->
    <rule ref="category/java/design.xml/CyclomaticComplexity">
        <properties>
            <property name="classReportLevel" value="80" />
            <property name="methodReportLevel" value="10" />
        </properties>
    </rule>
</ruleset>

Las reglas además admiten cierta configuración. En el fichero anterior verás que hemos cambiado algunas propiedades: Los umbrales a los que debe saltar la complejidad ciclomática a nivel de método y de clase.

Una vez hecho el fichero lo guardamos, por ejemplo, con nombre ciclomatica.xml en el directorio raiz de nuestro proyecto maven, junto al pom.xml. Modificamos el pom.xml para indicar a pmd que use este fichero. Quedaría así

<project>
...
   <reporting>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-pmd-plugin</artifactId>
            <configuration>
               <rulesets>
                  <ruleset>ciclomatica.xml</ruleset>
               </rulesets>
            </configuration>
         </plugin>
      </plugins>
   </reporting>
</project>

Ahora

mvn pmd:pmd

Hace lo mismo de antes, pero sólo nos avisa cuando la complejidad ciclomática de algún método supere los valores indicados.

Si no nos gusta esta ubicación de ciclomatica.xml, podemos ponerlo en otro directorio e indicar en el pom.xml dónde se encuentra.

Excluir determinadas reglas[editar]

Podemos hacer lo contrario, que se pasen todas las reglas por defecto, pero excluir alguna concreta. El siguiente fichero nos muestra cómo hacerlo

...
    <rule ref="category/java/bestpractices.xml">
        <exclude name="UnusedPrivateMethod"/>
    </rule>
...

No hemos puesto todo el fichero de configuración de reglas, sólo el trozo que deberíamos poner en él que configura la reglas. Al poner como ref="category/java/bestpractices.xml" estamos indicando que queremos todas las reglas de 'bestpractices.xml'. Y podemos poner <exclude> para excluir las que no queramos que se pasen.

Excluir determinadas clases o paquetes[editar]

A veces hay clases o paquetes enteros que no queremos que se le haga el análisis estático de código. Un ejemplo típico es código generado automáticamente por algún plugin. Podemos excluir clases y paquetes de la siguiente forma

<?xml version="1.0"?>
<ruleset name="Custom Rules"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">
    <description>
        Custom Rules
    </description>

    <exclude-pattern>.*/BackupMySQL\.java</exclude-pattern>
    <exclude-pattern>.*/arrays/.*</exclude-pattern>
 
    <!-- Aqui las reglas ... -->
    ...

Ponemos líneas <exclude-pattern y dentro una expresión regular que contenga nuestra estructura de paquetes (como directorios) y clases. En el ejemplo hemos puesto dos exclusiones

  • Se excluye de métricas la clase BackupMySQL.java en cualquier paquete que esté ( .*/ ). Como estamos con expresiones regulares y el punto tien un significado, hemos escapado el punto de .java
  • Se excluye de métricas cualquier clase que su paquete tenga arrays.

Cómo tener el listado de reglas de PMD[editar]

Vemos que podemos configurar las reglas, cuáles pasar, cuáles incluir, cuáles excluir, pero vemos también que es necesario conocer sus nombres. ¿De dónde sacamos este listado?

El sitio obvio es la web de pmd. Ahí están todas y si pinchas una de ellas, verás cómo referenciarla en el fichero de configuración de tu proyecto

Cómo referenciar una regla PMD en nuestro fichero de configuración
Cómo referenciar una regla PMD en nuestro fichero de configuración

Sin embargo, esto es bastante engorroso. Una forma más fácil de comenzar es buscar en nuestro proyecto la librería maven-pmd-plugin-3.21.2.jar, ver su contenido y buscar el fichero rulesets/java/maven-pmd-plugin-default.xml. Ojo, al ser un plugin de maven, probablemente no lo encuentres en tu proyecto montado en tu IDE favorito. En mi caso, para sacar la siguiente captura, he hecho un poco de trampa. He puesto la dependencia en el fichero pom.xml como una dependencia normal y no como un plugin.

Reglas por defecto de Maven para PMD
Reglas por defecto de Maven para PMD

Ahí ves las reglas que por defecto aplica maven-pmd-plugin. Puedes copiarlas a tu fichero y empezar a trabajar sobre ellas, añadiendo, excluyendo o modificando. Tienes este fichero también en el repositorio de fuentes de maven-pmd-plugin

Configuración de la versión de Java[editar]

pmd, según su versión, pasa métricas suponiendo que los fuentes son de determinada versión de Java. Para evitar problemas, suele ser buena idea configurar el plugin para que use la misma versión de java que nuestro pom.xml00. Para ello, en el pom.xml podemos poner lo siguiente:

...
				<plugin>
					<groupId>org.apache.maven.plugins</groupId>
					<artifactId>maven-pmd-plugin</artifactId>
					<version>3.21.2</version>
                    <configuration>
                        <targetJdk>${maven.compiler.target}</targetJdk>
                        ...
                    </configuration>
				</plugin>
...

Ten en cuenta que la versión de pmd no es la misma que la versión de maven-pmd-plugin. Para ver qué versión de pmd usa tu versión de maven-pmd-plugin, puedes ejecutar el comando mvn pmd:pmd y verlo en el log de salida

C:\>mvn pmd:pmd
[INFO] Scanning for projects...
...
[INFO] --- maven-pmd-plugin:3.21.2:pmd (default-cli) @ java-se-examples ---
...
[INFO] PMD version: 6.55.0
...

La siguiente tabla muestra las versiones por defecto de java según la versión de pmd.

Java Version Alias Supported by PMD since
21-preview   7.0.0
21 (default)   7.0.0
20-preview   6.55.0
20   6.55.0
19   6.48.0
18   6.44.0
17   6.37.0
16   6.32.0
15   6.27.0
14   6.22.0
13   6.18.0
12   6.13.0
11   6.6.0
10 1.10 6.4.0
9 1.9 6.0.0
8 1.8 5.1.0
7 1.7 5.0.0
6 1.6 3.9
5 1.5 3.0
1.4   1.2.2
1.3   1.0.0

Hacer que falle la compilación si no se cumplen las métricas[editar]

Podemos hacer que falle la compilación si no se cumplen las métricas. Los comandos mvn compile y mvn package funcionarán correctamente, pero mvn verify, mvn install o mvn deploy fallarán.

Para hacer esto, en nuestro fichero pom.xml debemos añadir algo así

<project>
...
   <build>
      <plugins>
         <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-pmd-plugin</artifactId>
            <configuration>
               <rulesets>
                  <ruleset>ciclomatica.xml</ruleset>
               </rulesets>
            </configuration>
            <executions>
               <execution>
                  <goals>
                     <goal>check</goal>
                  </goals>
               </execution>
            </executions>
         </plugin>
         ...
      </plugins>
      ...
   </build>
   ...
</project>

Al ejecutar el comando

mvn verify

o alguno de una fase superior (install o deploy), el proceso fallará indicando cuántas violaciones de código hemos cometido.

Enlaces externos[editar]