javamavenpmd

Cannot resolve rule/ruleset reference 'upstream.xml'. Make sure the resource is a valid file or URL and is on the CLASSPATH


I am confused about where PMD looks for ruleset files. I have some rulesets I am trying to reuse from an old project in a set of mavan projects. In that project the ruleset was referenced through a http url, but now I am trying to make one maven project to contain the rulesets, and reference it. I get the error in the title, however when I am looking at the classpath in the debug output of maven, it does not contain the place of the standard rulesets which resolve okay, and does contain the place where I am trying to put my ruleset.

my pmd.xml:

<ruleset name="Kode Konveyor WAR"
    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>PMD rules of Kode Konveyor</description>
<rule ref="category/java/bestpractices.xml"/>
<rule ref="upstream.xml"/>
<rule ref="konveyor.xml"/>
</ruleset>

the output of mvn pmd:pmd --debug contains:

[DEBUG] Using aux classpath: [/home/mag/project/civitas-ng/data/target/test-classes, /home/mag/project/civitas-ng/data/target/classes, /home/mag/.m2/repository/org/projectlombok/lombok/1.18.36/lombok-1.18.36.jar, /home/mag/.m2/repository/org/springframework/data/spring-data-keyvalue/4.0.0-M3/spring-data-keyvalue-4.0.0-M3.jar, /home/mag/.m2/repository/org/springframework/data/spring-data-commons/4.0.0-M3/spring-data-commons-4.0.0-M3.jar, /home/mag/.m2/repository/org/springframework/spring-core/7.0.0-M5/spring-core-7.0.0-M5.jar, /home/mag/.m2/repository/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar, /home/mag/.m2/repository/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar, /home/mag/.m2/repository/org/springframework/spring-beans/7.0.0-M5/spring-beans-7.0.0-M5.jar, /home/mag/.m2/repository/org/springframework/spring-context/7.0.0-M5/spring-context-7.0.0-M5.jar, /home/mag/.m2/repository/org/springframework/spring-aop/7.0.0-M5/spring-aop-7.0.0-M5.jar, /home/mag/.m2/repository/org/springframework/spring-expression/7.0.0-M5/spring-expression-7.0.0-M5.jar, /home/mag/.m2/repository/io/micrometer/micrometer-observation/1.15.0/micrometer-observation-1.15.0.jar, /home/mag/.m2/repository/io/micrometer/micrometer-commons/1.15.0/micrometer-commons-1.15.0.jar, /home/mag/.m2/repository/org/springframework/spring-tx/7.0.0-M5/spring-tx-7.0.0-M5.jar, /home/mag/.m2/repository/org/slf4j/slf4j-api/2.0.2/slf4j-api-2.0.2.jar, /home/mag/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.2/jakarta.xml.bind-api-4.0.2.jar, /home/mag/.m2/repository/jakarta/activation/jakarta.activation-api/2.1.3/jakarta.activation-api-2.1.3.jar, /home/mag/.m2/repository/io/github/magwas/konveyor-pmdrules/0.0.2-3-g5b9385b/konveyor-pmdrules-0.0.2-3-g5b9385b.jar]
[INFO] PMD version: 7.14.0
[DEBUG] Using language java+version:17
[DEBUG] Adding classpath entry: </home/mag/project/civitas-ng/data/target/test-classes>
[DEBUG] Adding classpath entry: </home/mag/project/civitas-ng/data/target/classes>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/projectlombok/lombok/1.18.36/lombok-1.18.36.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/data/spring-data-keyvalue/4.0.0-M3/spring-data-keyvalue-4.0.0-M3.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/data/spring-data-commons/4.0.0-M3/spring-data-commons-4.0.0-M3.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-core/7.0.0-M5/spring-core-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/commons-logging/commons-logging/1.3.5/commons-logging-1.3.5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/jspecify/jspecify/1.0.0/jspecify-1.0.0.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-beans/7.0.0-M5/spring-beans-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-context/7.0.0-M5/spring-context-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-aop/7.0.0-M5/spring-aop-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-expression/7.0.0-M5/spring-expression-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/io/micrometer/micrometer-observation/1.15.0/micrometer-observation-1.15.0.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/io/micrometer/micrometer-commons/1.15.0/micrometer-commons-1.15.0.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/springframework/spring-tx/7.0.0-M5/spring-tx-7.0.0-M5.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/org/slf4j/slf4j-api/2.0.2/slf4j-api-2.0.2.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/4.0.2/jakarta.xml.bind-api-4.0.2.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/jakarta/activation/jakarta.activation-api/2.1.3/jakarta.activation-api-2.1.3.jar>
[DEBUG] Adding classpath entry: </home/mag/.m2/repository/io/github/magwas/konveyor-pmdrules/0.0.2-3-g5b9385b/konveyor-pmdrules-0.0.2-3-g5b9385b.jar>

the contents of /home/mag/.m2/repository/io/github/magwas/konveyor-pmdrules/0.0.2-3-g5b9385b/konveyor-pmdrules-0.0.2-3-g5b9385b.jar:

Archive:  /home/mag/.m2/repository/io/github/magwas/konveyor-pmdrules/0.0.2-3-g5b9385b/konveyor-pmdrules-0.0.2-3-g5b9385b.jar
  Length      Date    Time    Name
---------  ---------- -----   ----
        0  2025-07-07 10:17   META-INF/
      127  2025-07-07 10:17   META-INF/MANIFEST.MF
    15920  2025-07-07 10:17   konveyor.xml
      420  2025-07-07 10:17   pmd.xml
     3642  2025-07-07 10:17   upstream.xml
        0  2025-07-07 10:17   META-INF/maven/
        0  2025-07-07 10:17   META-INF/maven/io.github.magwas/
        0  2025-07-07 10:17   META-INF/maven/io.github.magwas/konveyor-pmdrules/
      612  2025-07-07 10:15   META-INF/maven/io.github.magwas/konveyor-pmdrules/pom.xml
      130  2025-07-07 10:15   META-INF/maven/io.github.magwas/konveyor-pmdrules/pom.properties
---------                     -------
    20851                     10 files

I also tried to put upstream.xml into target/classes/upstream.xml directly with the same result.

the relevant parts of my pom.xml:

        </dependency>
                <dependency>
            <groupId>io.github.magwas</groupId>
            <artifactId>konveyor-pmdrules</artifactId>
            <version>${project.version}</version>
            </dependency>

    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-pmd-plugin</artifactId>
                <version>3.27.0</version>
                <configuration>
                    <minimumTokens>25</minimumTokens>
                    <ignoreAnnotations>true</ignoreAnnotations>
                    <includeTests>true</includeTests>
                    <rulesets>
                        <ruleset>pmd.xml</ruleset>
                    </rulesets>
                </configuration>
            </plugin>
        </plugins>
</build>

The debug output also contains this:

[DEBUG]   (f) typeResolution = true
[DEBUG] -- end configuration --

So as I understand the project's compile/test classpath should be passed to PMD, which is may or may not relevant here.

How do I make pmd find the referenced upstream.xml from the other project?


Solution

  • The jar-file konveyor-pmdrules-0.0.2-3-g5b9385b.jar looks fine. However, there are multiple different isolated classloaders in use, and you need to add the dependency to the correct classpath:

    When PMD is executing as part of the maven-pmd-plugin, it itself runs within the classloader for that plugin and sees only those dependencies - and not your application's dependencies. This is the classpath that is used to load the rulesets. That's the "runtime classpath".

    For analyzing your application, PMD also needs access to all the other application's dependencies - this is called the "auxiliary classpath" (auxclasspath). But this is not used to load the rulesets.

    So, you need to move the dependency io.github.magwas:konveyor-pmdrules to the plugin, like so:

        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-pmd-plugin</artifactId>
                    <version>3.27.0</version>
                    <configuration>
                        <minimumTokens>25</minimumTokens>
                        <ignoreAnnotations>true</ignoreAnnotations>
                        <includeTests>true</includeTests>
                        <rulesets>
                            <ruleset>pmd.xml</ruleset>
                        </rulesets>
                    </configuration>
                    <dependencies>
                        <dependency>
                            <groupId>io.github.magwas</groupId>
                            <artifactId>konveyor-pmdrules</artifactId>
                            <version>${project.version}</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </build>
    

    See also https://maven.apache.org/plugins/maven-pmd-plugin/examples/multi-module-config.html#Configure_the_other_projects_to_use_it for a more complex example.