Search code examples
javagradlebuild.gradlepmd

When 3rd party jar added in PMD Gradle classpath causes 'java.lang.ClassNotFoundException: net.sourceforge.pmd.PMD'


I tried to add 3rd party dependencies in gradle.properties as below

dependencies {
    pmd fileTree(dir: "${lib}/aspectj-1.9.4", includes: ['*.jar'])
     
    // OR below
   
    // pmd 'org.aspectj:aspectjtools:1.9.4'

    // OR even below also causes same problem.

    // pmdAux 'org.aspectj:aspectjtools:1.9.4'
}

It causes error as java.lang.ClassNotFoundException: net.sourceforge.pmd.PMD what can be issue here? how to overcome?

Ref:

  1. https://stackoverflow.com/a/17179486/1665592
  2. https://stackoverflow.com/a/71147569/1665592

Solution

  • It seems that all the dependencies in configuration pmd are replaced once you manually configure the dependency as in your example.

    In https://stackoverflow.com/a/71147569/1169968 is explained, that the gradle pmd plugin adds two dependencies configurations: pmd and pmdAux.

    pmd defines the classpath that is used to run PMD. It is by default setup by the plugin automatically, dependending on the toolVersion property (see PmdPlugin.java#L194-L201 and PmdPlugin.java#L145-L152). The gradle documentation about Declaring Dependencies explains, that "Many Gradle plugins add pre-defined configurations to your project". It also seems, that pmd is a default configuration, that is registered/created by AbstractCodeQualityPlugin.java#L98-L116. The configuration name is getToolName().toLowerCase() - so all code-quality plugins define a configuration with the same name as themselves.

    When declaring now a dependency like above, it seems that the previously configured dependencies are removed - or in other words: the configuration is replaced.

    I don't know, whether this is correct behavior or whether this is a bug. But it seems, once you start declaring such tool dependencies manually, you take over responsibility to declare the complete classpath for PMD. That makes sense, because then the "whole truth" is in your build.gradle/gradle.properties file. However, since the plugin also has the toolVersion property, this behavior is surprising: The toolVersion property is being ignored, once you declare the dependencies manually.

    To fix this, you just need to declare additionally the pmd dependency. So, the following works:

    dependencies {
        // first define the main PMD dependency
        pmd 'net.sourceforge.pmd:pmd-java:6.54.0'
    
        // then declare additional dependencies, e.g. to include your custom rule
        pmd 'com.example:myrule:1.0.0'
        // or
        pmd fileTree(dir: "${lib}/aspectj-1.9.4", includes: ['*.jar'])
        // OR below
        // pmd 'org.aspectj:aspectjtools:1.9.4'
    }
    

    Using toolVersion doesn't work anymore then. In order to use a different PMD version, you just need to update the version in the dependency then.

    Btw. I can't reproduce your problem with pmdAux - if the dependency is added to pmdAux, PMD is executed. However, it might not run correctly, as probably the same happens: the automatically calculated auxiliary classpath is thrown away and only your declared dependencies are used. That might result in false-positives/false-negatives due to type resolution not working correctly.