JavaLanguageModule
Usually the latest non-preview Java Version is the default version.
Java Version | Alias | Supported by PMD since |
---|---|---|
24-preview | 7.10.0 | |
24 (default) | 7.10.0 | |
23-preview | 7.5.0 | |
23 | 7.5.0 | |
22 | 7.0.0 | |
21 | 7.0.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 |
In order to analyze a project with PMD that uses preview language features, you’ll need to enableit via the environment variablePMD_JAVA_OPTS
and select the new language version, e.g.24-preview
:
export PMD_JAVA_OPTS=--enable-previewpmd check --use-version java-24-preview ...
Note: we only support preview language features for the latest two java versions.
Java being a statically typed language, a Java program contains more information than just its syntax tree;for instance, every expression has a static type, and every method call is bound to a method overloadstatically (even if that overload is virtual). In PMD, much of this information is resolved from the ASTby additional passes, which run after parsing, and before rules can inspect the tree.
The semantic analysis roughly works like so:
The analyzed code might reference types from other places of the project or even from externaldependencies. If e.g. the code extends a class from an external dependency, then PMD needs to knowthis external dependency in order to figure out, that a method is actually an override.
In order to resolve such types, a complete so-called auxiliary classpath need to be provided.Technically, PMD uses theASM framework to read the bytecode and buildup its own representation to resolve names and types. It also reads the bytecode of the Java runtimein order to resolve Java API references.
The auxiliary classpath (or short “auxClasspath”) is configured via theLanguage Property “auxClasspath”.It is a string containing multiple paths separated by either a colon (:
) under Linux/MacOSor a semicolon (;
) under Windows. This property can be provided on the CLI with parameter--aux-classpath
.
In order to resolve the types of the Java API correctly, the Java Runtime must be on theauxClasspath as well. As the Java API and Runtime evolves from version to version, it is importantto use the correct Java version, that is being analyzed. This might not necessarily be thesame Java runtime version that is being used to run PMD.
Until Java 8, there exists the jar filert.jar
in${JAVA_HOME}/jre/lib
. It is enough, to includethis jar file in the auxClasspath. Usually, you would add this as the first entry in the auxClasspath.
Beginning with Java 9, the Java platform has been modularized andModular Run-Time Imageshave been introduced. The file${JAVA_HOME}/lib/modules
contains now all the classes, but it is not a jar fileanymore. However, each Java installation provides an implementation to read such Run-Time Images in${JAVA_HOME}/lib/jrt-fs.jar
. This is an implementation of thejrt://
filesystem and through this, the bytecodeof the Java runtime classes can be loaded. In order to use this with PMD, the file${JAVA_HOME}/lib/jrt-fs.jar
needs to be added to the auxClasspath as the first entry. PMD will make sure, to load the Java runtime classesusing the jrt-filesystem.
If neither${JAVA_HOME}/jre/lib/rt.jar
nor${JAVA_HOME}/lib/jrt-fs.jar
is added to the auxClasspath, PMD fallsback to load the Java runtime classesfrom the current runtime, that is the runtime that was used toexecute PMD. This might not be the correct version, e.g. you might run PMD with Java 8, but analyze codewritten for Java 21. In that case, you have to provide “jrt-fs.jar” on the auxClasspath.
Not providing the correct auxClasspath might result in false positives or negatives for some rules,such asMissingOverride
.This rule needs to figure out, whether a method is defined already in the super class or interface. E.g. the methodCollection#toArray(IntFunction)has been added in Java 11, and it does not exist yet in Java 8. Given a simple subclass of ArrayList, that overridesthis method without adding@Override
, then PMD won’t be able to detect this missing override annotation, ifit is executed with a Java 8 runtime but without the correct auxClasspath. Providing the correctjrt-fs.jar
fromJava 11 (or later) for the auxClasspath allows PMD to correctly identify the missing annotation.
Example command line:
pmd check -d src/main/java \ --aux-classpath=path/to/java17/lib/jrt-fs.jar:target/classes/ \ -f xml -r pmd-report.xml -R rulesets/java/quickstart.xml
Symbol table API related classes are in the packagenet.sourceforge.pmd.lang.java.symbols
.The root interface for symbols isJElementSymbol
.
The symbol table can be requested on any node with the methodgetSymbolTable
.This returns aJSymbolTable
which gives you access to variables, methods and types that arewithin scope.
AASTExpression
might represent aASTAssignableExpr.ASTNamedReferenceExpr
if it e.g. references a variable name. In that case, you can access the referenced variable symbolwith the methodgetReferencedSym
.
Declaration nodes, such asASTVariableId
implement the interfaceSymbolDeclaratorNode
. Through the methodgetSymbol
you can also access the symbol.
To find usages, you can callgetLocalUsages
.
Type resolution API related classes are in the packagenet.sourceforge.pmd.lang.java.types
.
The core of the framework is a set of interfaces to represent types. The root interface isJTypeMirror
. Type mirrors are created by aTypeSystem
object. This object is analysis-global.
The utility classTypeTestUtil
provides simple methods to check types,e.g.TypeTestUtil.isA(String.class, variableDeclaratorIdNode)
tests, whether the givenvariableDeclaratorId is of type “String”.
AnyTypeNode
provides access to the type with the methodgetTypeMirror
.E.g. this can be called onASTMethodCall
to retrieve the return type of the called method.
In order to use code metrics in Java, use the metrics constants inJavaMetrics
,together withMetricsUtil
. For instance:
@OverridepublicObjectvisit(ASTMethodDeclarationnode,Objectdata){if(JavaMetrics.NCSS.supports(node)){intmethodSize=MetricsUtil.computeMetric(JavaMetrics.NCSS,node,ncssOptions);if(methodSize>=level){addViolation(data,node);}}returnnull;}
The Javadocs are the reference documentation.
Violations reported are the same for all languages, but languages can opt in to provide more details.Java does this by adding the following additional information for each reported violation:
You can access these viagetAdditionalInfo
There is no API yet for dataflow analysis. However, some rules such asUnusedAssignment
orImmutableField
are using an internal implementation of an additionalAST pass that adds dataflow information. The implementation can be found innet.sourceforge.pmd.lang.java.rule.internal.DataflowPass.