PMD Core - The foundational library module providing essential infrastructure for PMD static code analysis including AST handling, rule execution, configuration management, and reporting mechanisms.
—
The Utilities module provides essential helper classes and functions for common operations including parameter validation, string manipulation, file handling, version management, and other utility functions used throughout PMD Core.
Parameter validation and assertion utilities for defensive programming and error handling.
/**
* Utility methods for parameter validation and assertions.
* Provides consistent error messages and null checking across PMD.
*/
public final class AssertionUtil {
/**
* Check parameter is not null and return it
* @param paramName Name of parameter for error message
* @param param Parameter value to check
* @return The parameter value if not null
* @throws IllegalArgumentException if parameter is null
*/
static <T> T requireParamNotNull(String paramName, T param);
/**
* Check collection contains no null values
* @param paramName Name of parameter for error message
* @param collection Collection to validate
* @throws IllegalArgumentException if collection contains null elements
*/
static <T> void requireContainsNoNullValue(String paramName, Collection<T> collection);
/**
* Create "unreachable code" assertion error
* @return AssertionError indicating code should not be reached
*/
static AssertionError shouldNotReachHere();
/**
* Create "unreachable code" assertion error with message
* @param message Descriptive message for the error
* @return AssertionError with custom message
*/
static AssertionError shouldNotReachHere(String message);
/**
* Create "unreachable code" assertion error with message and cause
* @param message Descriptive message for the error
* @param cause Underlying cause of the error
* @return AssertionError with message and cause
*/
static AssertionError shouldNotReachHere(String message, Throwable cause);
}Usage Examples:
import net.sourceforge.pmd.util.AssertionUtil;
import java.util.List;
import java.util.Arrays;
// Using assertion utilities in methods
public class ValidationExample {
public void processData(String name, List<String> items, Object config) {
// Validate required parameters
name = AssertionUtil.requireParamNotNull("name", name);
items = AssertionUtil.requireParamNotNull("items", items);
config = AssertionUtil.requireParamNotNull("config", config);
// Validate collection contents
AssertionUtil.requireContainsNoNullValue("items", items);
// Process with confidence that parameters are valid
processValidatedData(name, items, config);
}
private void processValidatedData(String name, List<String> items, Object config) {
// Implementation assumes all parameters are non-null
System.out.printf("Processing %s with %d items%n", name, items.size());
}
public String handleDifferentCases(int caseType) {
switch (caseType) {
case 1:
return "Case 1";
case 2:
return "Case 2";
case 3:
return "Case 3";
default:
// This should never happen based on our design
throw AssertionUtil.shouldNotReachHere(
"Unexpected case type: " + caseType);
}
}
public void demonstrateErrorHandling() {
try {
processData(null, Arrays.asList("a", "b"), new Object());
} catch (IllegalArgumentException e) {
System.err.println("Expected error: " + e.getMessage());
}
try {
processData("test", Arrays.asList("a", null, "c"), new Object());
} catch (IllegalArgumentException e) {
System.err.println("Expected error: " + e.getMessage());
}
try {
handleDifferentCases(99); // Invalid case
} catch (AssertionError e) {
System.err.println("Unreachable code error: " + e.getMessage());
}
}
}
// Using in custom rule implementation
public class CustomRuleExample extends AbstractRule {
@Override
public void apply(List<? extends Node> nodes, RuleContext ctx) {
// Validate inputs
nodes = AssertionUtil.requireParamNotNull("nodes", nodes);
ctx = AssertionUtil.requireParamNotNull("ctx", ctx);
AssertionUtil.requireContainsNoNullValue("nodes", nodes);
// Safe to proceed with analysis
for (Node node : nodes) {
analyzeNode(node, ctx);
}
}
private void analyzeNode(Node node, RuleContext ctx) {
// Implementation can assume node and ctx are non-null
if (node.getNumChildren() == 0) {
ctx.addViolation(node, "Empty node found");
}
}
}String manipulation utilities for common text processing operations.
/**
* String manipulation utilities for common text operations.
* Provides null-safe methods for string validation and processing.
*/
public final class StringUtil {
/**
* Check if string is null or empty
* @param str String to check
* @return true if string is null or has length 0
*/
static boolean isEmpty(String str);
/**
* Check if string is not null and not empty
* @param str String to check
* @return true if string is not null and has length > 0
*/
static boolean isNotEmpty(String str);
/**
* Check if string is null, empty, or contains only whitespace
* @param str String to check
* @return true if string is null, empty, or whitespace-only
*/
static boolean isBlank(String str);
/**
* Check if string has non-whitespace content
* @param str String to check
* @return true if string contains non-whitespace characters
*/
static boolean isNotBlank(String str);
/**
* Quote string for MessageFormat (escape single quotes)
* @param msg String to quote for MessageFormat usage
* @return String with single quotes escaped
*/
static String quoteMessageFormat(String msg);
/**
* Replace all occurrences of substring
* @param original Source string
* @param find Substring to find
* @param replacement Replacement string
* @return String with all occurrences replaced
*/
static String replaceString(String original, String find, String replacement);
/**
* Split string by character separator
* @param str String to split
* @param separator Character to split on
* @return List of split parts (empty list if input is null/empty)
*/
static List<String> split(String str, char separator);
}Usage Examples:
import net.sourceforge.pmd.util.StringUtil;
import java.util.List;
// Using string utilities
public class StringProcessingExample {
public void validateInput(String userInput) {
if (StringUtil.isEmpty(userInput)) {
throw new IllegalArgumentException("Input cannot be empty");
}
if (StringUtil.isBlank(userInput)) {
System.out.println("Warning: Input is only whitespace");
return;
}
// Process valid input
processValidInput(userInput.trim());
}
public void processConfiguration(String configValue) {
// Check for meaningful content
if (StringUtil.isNotBlank(configValue)) {
System.out.printf("Processing config: '%s'%n", configValue);
// Split configuration values
List<String> parts = StringUtil.split(configValue, ',');
System.out.printf("Configuration has %d parts:%n", parts.size());
for (int i = 0; i < parts.size(); i++) {
String part = parts.get(i).trim();
if (StringUtil.isNotEmpty(part)) {
System.out.printf(" Part %d: %s%n", i + 1, part);
}
}
} else {
System.out.println("No configuration provided");
}
}
public String formatMessage(String template, String userValue) {
// Prepare message for MessageFormat
String quotedTemplate = StringUtil.quoteMessageFormat(template);
// Replace placeholder with actual value
return StringUtil.replaceString(quotedTemplate, "{value}", userValue);
}
public void demonstrateStringOperations() {
// Test empty/blank detection
testString(null, "null string");
testString("", "empty string");
testString(" ", "whitespace string");
testString("hello", "normal string");
// Test splitting
String csvData = "apple,banana,cherry,date";
List<String> fruits = StringUtil.split(csvData, ',');
System.out.printf("CSV '%s' split into: %s%n", csvData, fruits);
// Test replacement
String original = "Hello {name}, welcome to {place}!";
String replaced = StringUtil.replaceString(original, "{name}", "Alice");
replaced = StringUtil.replaceString(replaced, "{place}", "PMD");
System.out.printf("Template: %s%nResult: %s%n", original, replaced);
// Test MessageFormat quoting
String messageTemplate = "Don't use 'System.out.println'";
String quoted = StringUtil.quoteMessageFormat(messageTemplate);
System.out.printf("Original: %s%nQuoted: %s%n", messageTemplate, quoted);
}
private void testString(String str, String description) {
System.out.printf("%s:%n", description);
System.out.printf(" isEmpty: %b%n", StringUtil.isEmpty(str));
System.out.printf(" isNotEmpty: %b%n", StringUtil.isNotEmpty(str));
System.out.printf(" isBlank: %b%n", StringUtil.isBlank(str));
System.out.printf(" isNotBlank: %b%n", StringUtil.isNotBlank(str));
}
private void processValidInput(String input) {
System.out.printf("Processing valid input: '%s'%n", input);
}
}
// Using in rule message formatting
public class MessageFormattingExample {
public void formatRuleMessage(String template, Object... args) {
// Quote template for MessageFormat
String quotedTemplate = StringUtil.quoteMessageFormat(template);
// Format with arguments
String message = MessageFormat.format(quotedTemplate, args);
System.out.println("Formatted message: " + message);
}
public void processRuleViolation(RuleViolation violation) {
String description = violation.getDescription();
if (StringUtil.isNotBlank(description)) {
// Clean up the description
description = description.trim();
// Remove PMD-specific markers if present
description = StringUtil.replaceString(description, "PMD:", "");
description = description.trim();
System.out.printf("Clean violation: %s%n", description);
}
}
}Version information and utilities for PMD versioning and compatibility checking.
/**
* PMD version information and utilities.
* Provides access to current version and version-related operations.
*/
public final class PMDVersion {
/**
* Current PMD version string
*/
public static final String VERSION;
/**
* Get next expected major version
* @return Next major version string
*/
static String getNextMajorRelease();
/**
* Check if current version is unknown
* @return true if version information is not available
*/
static boolean isUnknown();
/**
* Check if current version is a snapshot build
* @return true if version contains snapshot indicators
*/
static boolean isSnapshot();
/**
* Get full version string with metadata
* @return Complete version string including build information
*/
static String getFullVersionName();
}Usage Examples:
import net.sourceforge.pmd.PMDVersion;
// Working with version information
public class VersionExample {
public void displayVersionInfo() {
System.out.println("PMD Version Information:");
System.out.printf(" Current version: %s%n", PMDVersion.VERSION);
System.out.printf(" Full version: %s%n", PMDVersion.getFullVersionName());
System.out.printf(" Next major: %s%n", PMDVersion.getNextMajorRelease());
System.out.printf(" Is snapshot: %b%n", PMDVersion.isSnapshot());
System.out.printf(" Is unknown: %b%n", PMDVersion.isUnknown());
}
public void checkCompatibility(String requiredVersion) {
String currentVersion = PMDVersion.VERSION;
if (PMDVersion.isUnknown()) {
System.out.println("Warning: PMD version is unknown");
return;
}
if (PMDVersion.isSnapshot()) {
System.out.println("Note: Using snapshot version - features may be unstable");
}
// Simple version comparison (real implementation would be more sophisticated)
if (currentVersion.equals(requiredVersion)) {
System.out.printf("✓ Version %s matches requirement%n", currentVersion);
} else {
System.out.printf("⚠ Version %s does not match requirement %s%n",
currentVersion, requiredVersion);
}
}
public void generateBuildInfo() {
System.out.println("Build Information:");
System.out.printf("PMD Core %s%n", PMDVersion.getFullVersionName());
if (PMDVersion.isSnapshot()) {
System.out.println("This is a development build - not for production use");
} else {
System.out.println("This is a release build");
}
}
}Extended rendering system with comprehensive output format support including XML, HTML, JSON, CSV, and specialized formats.
/**
* Extensible rendering framework for formatting analysis reports.
* Provides multiple output formats with customizable properties.
*/
public interface Renderer extends PropertySource {
/**
* Get renderer name/identifier
* @return Unique name for the renderer
*/
String getName();
/**
* Set renderer name
* @param name Unique identifier for renderer
*/
void setName(String name);
/**
* Get renderer description
* @return Human-readable description of renderer purpose
*/
String getDescription();
/**
* Set renderer description
* @param description Description of renderer functionality
*/
void setDescription(String description);
/**
* Get default file extension for output
* @return File extension without dot (e.g., "xml", "html")
*/
String defaultFileExtension();
/**
* Check if suppressed violations are shown
* @return true if renderer includes suppressed violations
*/
boolean isShowSuppressedViolations();
/**
* Set whether to show suppressed violations
* @param show true to include suppressed violations in output
*/
void setShowSuppressedViolations(boolean show);
/**
* Set output writer for rendering
* @param writer Writer for formatted output
*/
void setWriter(Writer writer);
/**
* Set report file path (alternative to setWriter)
* @param reportFile Path to output file
*/
void setReportFile(String reportFile);
/**
* Create analysis listener for receiving events
* @return GlobalAnalysisListener that forwards to this renderer
*/
GlobalAnalysisListener newListener();
/**
* Start rendering process
*/
void start();
/**
* End rendering process
*/
void end();
/**
* Flush any buffered output
*/
void flush();
}/**
* File identifier and metadata
*/
interface FileId {
/**
* Get absolute file path
* @return Absolute path to the file
*/
String getAbsolutePath();
/**
* Get display name for reports
* @return User-friendly file name for display
*/
String getDisplayName();
/**
* Get file URI
* @return URI representation of file location
*/
URI getUri();
/**
* Create FileId from path-like string
* @param pathLike String representing file path
* @return FileId instance
*/
static FileId fromPathLikeString(String pathLike);
/**
* Create FileId from Path object
* @param path Path object representing file
* @return FileId instance
*/
static FileId fromPath(Path path);
}
/**
* Text document representation
*/
interface TextDocument {
/**
* Get complete document text
* @return Full text content
*/
String getText();
/**
* Get text for specific region
* @param region TextRegion to extract
* @return Text content for region
*/
String getText(TextRegion region);
/**
* Get line content by number
* @param lineNumber One-based line number
* @return Content of specified line
*/
String getLine(int lineNumber);
/**
* Get total line count
* @return Number of lines in document
*/
int getLineCount();
/**
* Get file identifier
* @return FileId for this document
*/
FileId getFileId();
}
/**
* Collection utilities for common operations
*/
final class CollectionUtil {
/**
* Create immutable list from array
* @param items Array elements
* @return Unmodifiable List containing elements
*/
static <T> List<T> listOf(T... items);
/**
* Check if collection is null or empty
* @param collection Collection to check
* @return true if collection is null or empty
*/
static boolean isEmpty(Collection<?> collection);
/**
* Get first element of list
* @param list List to query
* @return First element or null if empty
*/
static <T> T first(List<T> list);
/**
* Get last element of list
* @param list List to query
* @return Last element or null if empty
*/
static <T> T last(List<T> list);
}
/**
* I/O utilities for file operations
*/
final class IOUtil {
/**
* Read entire file as string
* @param file File to read
* @param charset Character encoding to use
* @return File contents as string
*/
static String readFileToString(File file, Charset charset) throws IOException;
/**
* Write string to file
* @param file Target file
* @param content Content to write
* @param charset Character encoding to use
*/
static void writeStringToFile(File file, String content, Charset charset) throws IOException;
/**
* Close resource quietly (ignoring exceptions)
* @param closeable Resource to close
*/
static void closeQuietly(Closeable closeable);
/**
* Copy input stream to output stream
* @param input Source stream
* @param output Target stream
* @return Number of bytes copied
*/
static long copy(InputStream input, OutputStream output) throws IOException;
}
/**
* Date/time utilities for timestamps
*/
final class DateTimeUtil {
/**
* Format timestamp for reports
* @param timestamp Timestamp to format
* @return Formatted timestamp string
*/
static String formatTimestamp(long timestamp);
/**
* Get current timestamp
* @return Current system time in milliseconds
*/
static long getCurrentTimestamp();
/**
* Parse ISO date string
* @param dateString ISO-formatted date
* @return Parsed timestamp
*/
static long parseISODate(String dateString);
}
/**
* System utilities for environment access
*/
final class SystemUtil {
/**
* Get system property with default
* @param key Property key
* @param defaultValue Default if property not set
* @return Property value or default
*/
static String getSystemProperty(String key, String defaultValue);
/**
* Check if running on Windows
* @return true if Windows operating system
*/
static boolean isWindows();
/**
* Get available processor count
* @return Number of available processors
*/
static int getAvailableProcessors();
/**
* Get total system memory
* @return Total memory in bytes
*/
static long getTotalMemory();
}
/**
* Mathematical utilities for calculations
*/
final class MathUtil {
/**
* Calculate percentage
* @param part Numerator value
* @param total Denominator value
* @return Percentage (0-100)
*/
static double percentage(long part, long total);
/**
* Clamp value to range
* @param value Value to clamp
* @param min Minimum allowed value
* @param max Maximum allowed value
* @return Clamped value within range
*/
static int clamp(int value, int min, int max);
/**
* Check if number is in range (inclusive)
* @param value Value to check
* @param min Minimum value
* @param max Maximum value
* @return true if value is within range
*/
static boolean inRange(int value, int min, int max);
}Install with Tessl CLI
npx tessl i tessl/maven-net-sourceforge-pmd--pmd-core