Merge branch 'docs-java-api'

Refs #2283
This commit is contained in:
Clément Fournier
2020-02-14 23:57:38 +01:00
4 changed files with 355 additions and 2 deletions

View File

@ -0,0 +1,64 @@
---
title: Gradle
tags: [userdocs, tools]
permalink: pmd_userdocs_tools_gradle.html
---
The [Gradle Build Tool](https://gradle.org/) provides a [PMD Plugin](https://docs.gradle.org/current/userguide/pmd_plugin.html)
that can be added to your build configuration. Technically it is based on the [Ant Task](pmd_userdocs_tools_ant.html).
## Example
In your `build.gradle` add the following:
```
plugins {
id 'pmd'
}
```
### Custom ruleset
Configuration of a custom ruleset looks like this:
```
pmd {
ruleSetFiles = files("custom-pmd-ruleset.xml")
ruleSets = []
}
```
Note: The `ruleSets` array is explicitly set to empty to avoid using the default configuration.
### Fail the build
If you want to fail the build for pmd violations, you need to set `ignoreFailures`:
```
pmd {
ignoreFailures = false
}
```
More configuration options are documented on [PMD Extension](https://docs.gradle.org/current/dsl/org.gradle.api.plugins.quality.PmdExtension.html).
### Upgrade PMD version
If you want to use a newer PMD version than the default one provided with gradle, you can do so
with the property `toolVersion`:
```
pmd {
toolVersion = "6.21.0"
}
```
## References
Source code for Gradles PMD Plugin is available here:
* [gradle/gradle code-quality](https://github.com/gradle/gradle/tree/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality)
* [Pmd.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/Pmd.java)
* [PmdExtension.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdExtension.java)
* [PmdPlugin.java](https://github.com/gradle/gradle/blob/master/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java)
* The default PMD version used by gradle: [DEFAULT_PMD_VERSION](https://github.com/gradle/gradle/blob/62297596035d0ed59304bf458eb89bb9859bb3e3/subprojects/code-quality/src/main/groovy/org/gradle/api/plugins/quality/PmdPlugin.java#L51)

View File

@ -0,0 +1,283 @@
---
title: PMD Java API
tags: [userdocs, tools]
permalink: pmd_userdocs_tools_java_api.html
---
The easiest way to run PMD is to just use a build plugin in your favorite build tool
like [Apache Ant](pmd_userdocs_tools_ant.html), [Apache Maven](pmd_userdocs_tools_maven.html) or
[Gradle](pmd_userdocs_tools_gradle.html).
There are also many integrations for IDEs available, see [Tools](pmd_userdocs_tools.html).
If you have your own build tool or want to integrate PMD in a different way, you can call PMD programmatically,
as described here.
## Dependencies
You'll need to add the dependency to the language, you want to analyze. For Java, it will be
`net.sourceforge.pmd:pmd-java`. If you use Maven, you can add a new (compile time) dependency like this:
``` xml
<dependency>
<groupId>net.sourceforge.pmd</groupId>
<artifactId>pmd-java</artifactId>
<version>${pmdVersion}</version>
</dependency>
```
Note: You'll need to select a specific version. This is done in the example via the property `pmdVersion`.
This will transitively pull in the artifact `pmd-core` which contains the API.
## Command line interface
The easiest way is to call PMD with the same interface as from command line. The main class is
`net.sourceforge.pmd.PMD`:
``` java
import net.sourceforge.pmd.PMD;
public class Example {
public static void main(String[] args) {
String[] pmdArgs = {
"-d", "/home/workspace/src/main/java/code",
"-R", "rulesets/java/quickstart.xml",
"-f", "xml",
"-r", "/home/workspace/pmd-report.xml"
};
PMD.main(pmdArgs);
}
}
```
It uses the same options as described in [PMD CLI reference](pmd_userdocs_cli_reference.html).
## Programmatically, variant 1
This is very similar:
``` java
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
public class PmdExample {
public static void main(String[] args) {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setInputPaths("/home/workspace/src/main/java/code");
configuration.setRuleSets("rulesets/java/quickstart.xml");
configuration.setReportFormat("xml");
configuration.setReportFile("/home/workspace/pmd-report.xml");
PMD.doPMD(configuration);
}
}
```
## Programmatically, variant 2
This gives you more control over which files are processed, but is also more complicated.
You can also provide your own listeners and renderers.
1. First we create a `PMDConfiguration`. This is currently the only way to specify a ruleset:
```java
PMDConfiguration configuration = new PMDConfiguration();
configuration.setMinimumPriority(RulePriority.MEDIUM);
configuration.setRuleSets("rulesets/java/quickstart.xml");
```
2. In order to support type resolution, PMD needs to have access to the compiled classes and dependencies
as well. This is called "auxclasspath" and is also configured here.
Note: you can specify multiple class paths separated by `:` on Unix-systems or `;` under Windows.
```java
configuration.prependClasspath("/home/workspace/target/classes:/home/.m2/repository/my/dependency.jar");
```
3. Then we need a ruleset factory. This is created using the configuration, taking the minimum priority into
account:
```java
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration);
```
4. PMD operates on a list of `DataSource`. You can assemble a own list of `FileDataSource`, e.g.
```java
List<DataSource> files = Arrays.asList(new FileDataSource(new File("/path/to/src/MyClass.java")));
```
5. For reporting, you can use a built-in renderer, e.g. `XMLRenderer`. Note, that you must manually initialize
the renderer by setting a suitable `Writer` and calling `start()`. After the PMD run, you need to call
`end()` and `flush()`. Then your writer should have received all output.
```java
StringWriter rendererOutput = new StringWriter();
Renderer xmlRenderer = new XMLRenderer("UTF-8");
xmlRenderer.setWriter(rendererOutput);
xmlRenderer.start();
```
6. Create a `RuleContext`. This is the context instance, that is available then in the rule implementations.
Note: when running in multi-threaded mode (which is the default), the rule context instance is cloned for
each thread.
```java
RuleContext ctx = new RuleContext();
```
7. Optionally register a report listener. This allows you to react immediately on found violations. You could also
use such a listener to implement your own renderer. The listener must implement the interface
`ThreadSafeReportListener` and can be registered via `ctx.getReport().addListener(...)`.
```java
ctx.getReport().addListener(new ThreadSafeReportListener() {
public void ruleViolationAdded(RuleViolation ruleViolation) {
}
public void metricAdded(Metric metric) {
}
```
8. Now, all the preparations are done, and PMD can be executed. This is done by calling
`PMD.processFiles(...)`. This method call takes the configuration, the ruleset factory, the files
to process, the rule context and the list of renderers. Provide an empty list, if you don't want to use
any renderer. Note: The auxclasspath needs to be closed explicitly. Otherwise the class or jar files may
remain open and file resources are leaked.
```java
try {
PMD.processFiles(configuration, ruleSetFactory, files, ctx,
Collections.singletonList(renderer));
} finally {
ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
((ClasspathClassLoader) auxiliaryClassLoader).close();
}
}
```
9. After the call, you need to finish the renderer via `end()` and `flush()`.
Then you can check the rendered output.
``` java
renderer.end();
renderer.flush();
System.out.println("Rendered Report:");
System.out.println(rendererOutput.toString());
```
Here is a complete example:
``` java
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.nio.file.FileSystems;
import java.nio.file.FileVisitResult;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.PathMatcher;
import java.nio.file.SimpleFileVisitor;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import net.sourceforge.pmd.PMD;
import net.sourceforge.pmd.PMDConfiguration;
import net.sourceforge.pmd.RuleContext;
import net.sourceforge.pmd.RulePriority;
import net.sourceforge.pmd.RuleSetFactory;
import net.sourceforge.pmd.RuleViolation;
import net.sourceforge.pmd.RulesetsFactoryUtils;
import net.sourceforge.pmd.ThreadSafeReportListener;
import net.sourceforge.pmd.renderers.Renderer;
import net.sourceforge.pmd.renderers.XMLRenderer;
import net.sourceforge.pmd.stat.Metric;
import net.sourceforge.pmd.util.ClasspathClassLoader;
import net.sourceforge.pmd.util.datasource.DataSource;
import net.sourceforge.pmd.util.datasource.FileDataSource;
public class PmdExample2 {
public static void main(String[] args) throws IOException {
PMDConfiguration configuration = new PMDConfiguration();
configuration.setMinimumPriority(RulePriority.MEDIUM);
configuration.setRuleSets("rulesets/java/quickstart.xml");
configuration.prependClasspath("/home/workspace/target/classes");
RuleSetFactory ruleSetFactory = RulesetsFactoryUtils.createFactory(configuration);
List<DataSource> files = determineFiles("/home/workspace/src/main/java/code");
Writer rendererOutput = new StringWriter();
Renderer renderer = createRenderer(rendererOutput);
renderer.start();
RuleContext ctx = new RuleContext();
ctx.getReport().addListener(createReportListener()); // alternative way to collect violations
try {
PMD.processFiles(configuration, ruleSetFactory, files, ctx,
Collections.singletonList(renderer));
} finally {
ClassLoader auxiliaryClassLoader = configuration.getClassLoader();
if (auxiliaryClassLoader instanceof ClasspathClassLoader) {
((ClasspathClassLoader) auxiliaryClassLoader).close();
}
}
renderer.end();
renderer.flush();
System.out.println("Rendered Report:");
System.out.println(rendererOutput.toString());
}
private static ThreadSafeReportListener createReportListener() {
return new ThreadSafeReportListener() {
@Override
public void ruleViolationAdded(RuleViolation ruleViolation) {
System.out.printf("%-20s:%d %s%n", ruleViolation.getFilename(),
ruleViolation.getBeginLine(), ruleViolation.getDescription());
}
@Override
public void metricAdded(Metric metric) {
// ignored
}
};
}
private static Renderer createRenderer(Writer writer) {
XMLRenderer xml = new XMLRenderer("UTF-8");
xml.setWriter(writer);
return xml;
}
private static List<DataSource> determineFiles(String basePath) throws IOException {
Path dirPath = FileSystems.getDefault().getPath(basePath);
PathMatcher matcher = FileSystems.getDefault().getPathMatcher("glob:*.java");
List<DataSource> files = new ArrayList<>();
Files.walkFileTree(dirPath, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path path, BasicFileAttributes attrs) throws IOException {
if (matcher.matches(path.getFileName())) {
System.out.printf("Using %s%n", path);
files.add(new FileDataSource(path.toFile()));
} else {
System.out.printf("Ignoring %s%n", path);
}
return super.visitFile(path, attrs);
}
});
System.out.printf("Analyzing %d files in %s%n", files.size(), basePath);
return files;
}
}
```

View File

@ -1,7 +1,7 @@
---
title: Maven PMD Plugin
tags: [userdocs, tools]
permalink: /pmd_userdocs_tools_maven.html
permalink: pmd_userdocs_tools_maven.html
last_updated: August 2017
author: >
Miguel Griffa <mikkey@users.sourceforge.net>,