CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-net-sourceforge-pmd--pmd-core

PMD Core - The foundational library module providing essential infrastructure for PMD static code analysis including AST handling, rule execution, configuration management, and reporting mechanisms.

Pending
Overview
Eval results
Files

rendering-system.mddocs/

Rendering System

The Rendering System provides extensible infrastructure for formatting PMD analysis reports in various output formats. It includes a base renderer interface, built-in format implementations, and customizable properties for different output requirements.

Capabilities

Renderer Interface

Core interface for formatting PMD reports with support for multiple output formats and configurable properties.

/**
 * Interface for rendering PMD reports in various formats.
 * Extends PropertySource to support configurable rendering options.
 */
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 (write headers, opening tags, etc.)
     */
    void start();
    
    /**
     * End rendering process (write footers, closing tags, etc.)
     */
    void end();
    
    /**
     * Flush any buffered output
     */
    void flush();
}

Usage Examples:

import net.sourceforge.pmd.renderers.*;
import net.sourceforge.pmd.*;
import java.io.*;

// Basic renderer usage
public class RendererExample {
    
    public void useXMLRenderer() throws IOException {
        // Create XML renderer
        XMLRenderer xmlRenderer = new XMLRenderer();
        xmlRenderer.setName("xml-report");
        xmlRenderer.setDescription("XML format report");
        
        // Configure output
        FileWriter writer = new FileWriter("pmd-report.xml");
        xmlRenderer.setWriter(writer);
        xmlRenderer.setShowSuppressedViolations(true);
        
        // Use with PMD analysis
        PMDConfiguration config = new PMDConfiguration();
        config.addInputPath(Paths.get("src/main/java"));
        config.addRuleSet("rulesets/java/quickstart.xml");
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            analysis.addRenderer(xmlRenderer);
            analysis.files().addDirectory(Paths.get("src/main/java"));
            
            RuleSetLoader loader = analysis.newRuleSetLoader();
            analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
            
            // Execute analysis - results go to XML renderer
            analysis.performAnalysis();
        } finally {
            writer.close();
        }
    }
    
    public void useMultipleRenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        config.addInputPath(Paths.get("src"));
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // Add multiple renderers for different formats
            
            // XML renderer
            XMLRenderer xmlRenderer = new XMLRenderer();
            xmlRenderer.setWriter(new FileWriter("report.xml"));
            analysis.addRenderer(xmlRenderer);
            
            // HTML renderer  
            HTMLRenderer htmlRenderer = new HTMLRenderer();
            htmlRenderer.setWriter(new FileWriter("report.html"));
            analysis.addRenderer(htmlRenderer);
            
            // Text renderer for console output
            TextRenderer textRenderer = new TextRenderer();
            textRenderer.setWriter(new OutputStreamWriter(System.out));
            analysis.addRenderer(textRenderer);
            
            // JSON renderer
            JsonRenderer jsonRenderer = new JsonRenderer();
            jsonRenderer.setWriter(new FileWriter("report.json"));
            analysis.addRenderer(jsonRenderer);
            
            // Configure analysis and run
            analysis.files().addDirectory(Paths.get("src"));
            RuleSetLoader loader = analysis.newRuleSetLoader();
            analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
            
            analysis.performAnalysis();
        }
    }
    
    public void configureRendererProperties() {
        // Configure HTML renderer with custom properties
        HTMLRenderer htmlRenderer = new HTMLRenderer();
        
        // Set renderer properties (if supported)
        Properties props = new Properties();
        props.setProperty("linkPrefix", "https://github.com/myorg/myrepo/blob/main/");
        props.setProperty("linePrefix", "#L");
        props.setProperty("title", "PMD Analysis Report");
        
        // Apply properties to renderer (method depends on specific renderer)
        htmlRenderer.getPropertyDescriptors().forEach(desc -> {
            String value = props.getProperty(desc.name());
            if (value != null && desc.type() == String.class) {
                @SuppressWarnings("unchecked")
                PropertyDescriptor<String> stringDesc = (PropertyDescriptor<String>) desc;
                htmlRenderer.setProperty(stringDesc, value);
            }
        });
        
        System.out.printf("Configured %s with %d properties%n", 
            htmlRenderer.getName(), 
            htmlRenderer.getPropertyDescriptors().size());
    }
}

Built-in Renderers

PMD provides numerous built-in renderers for different output formats and integration scenarios.

/**
 * Built-in renderer implementations for various output formats
 */

/**
 * XML renderer for structured XML output
 */
class XMLRenderer implements Renderer {
    XMLRenderer();
    XMLRenderer(String name);
}

/**
 * HTML renderer with styling and hyperlinks
 */
class HTMLRenderer implements Renderer {
    HTMLRenderer();
    HTMLRenderer(String name);
}

/**
 * Simple text renderer for plain text output
 */
class TextRenderer implements Renderer {
    TextRenderer();
    TextRenderer(String name);
}

/**
 * Colored text renderer with ANSI color codes
 */
class TextColorRenderer implements Renderer {
    TextColorRenderer();
    TextColorRenderer(Properties colorSettings);
}

/**
 * CSV renderer for comma-separated values
 */
class CSVRenderer implements Renderer {
    CSVRenderer();
}

/**
 * JSON renderer for structured JSON output
 */
class JsonRenderer implements Renderer {
    JsonRenderer();
}

/**
 * SARIF renderer for Static Analysis Results Interchange Format
 */
class SarifRenderer implements Renderer {
    SarifRenderer();
}

/**
 * GNU Emacs integration renderer
 */
class EmacsRenderer implements Renderer {
    EmacsRenderer();
}

/**
 * IntelliJ IDEA integration renderer
 */
class IDEAJRenderer implements Renderer {
    IDEAJRenderer();
}

/**
 * Empty renderer that produces no output (silent mode)
 */
class EmptyRenderer implements Renderer {
    EmptyRenderer();
}

/**
 * Code Climate renderer for CI/CD integration
 */
class CodeClimateRenderer implements Renderer {
    CodeClimateRenderer();
}

Usage Examples:

import net.sourceforge.pmd.renderers.*;
import java.io.*;
import java.util.Properties;

// Using different built-in renderers
public class BuiltInRenderersExample {
    
    public void demonstrateTextRenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // Simple text renderer
            TextRenderer textRenderer = new TextRenderer();
            textRenderer.setWriter(new FileWriter("report.txt"));
            analysis.addRenderer(textRenderer);
            
            // Colored text renderer for console
            Properties colorProps = new Properties();
            colorProps.setProperty("color.high", "red");
            colorProps.setProperty("color.medium", "yellow");
            colorProps.setProperty("color.low", "blue");
            
            TextColorRenderer colorRenderer = new TextColorRenderer(colorProps);
            colorRenderer.setWriter(new OutputStreamWriter(System.out));
            analysis.addRenderer(colorRenderer);
            
            // Configure and run analysis...
            setupAndRunAnalysis(analysis);
        }
    }
    
    public void demonstrateStructuredRenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // XML renderer
            XMLRenderer xmlRenderer = new XMLRenderer("detailed-xml");
            xmlRenderer.setWriter(new FileWriter("detailed-report.xml"));
            xmlRenderer.setShowSuppressedViolations(true);
            analysis.addRenderer(xmlRenderer);
            
            // JSON renderer
            JsonRenderer jsonRenderer = new JsonRenderer();
            jsonRenderer.setWriter(new FileWriter("report.json"));
            analysis.addRenderer(jsonRenderer);
            
            // SARIF renderer for security tools
            SarifRenderer sarifRenderer = new SarifRenderer();
            sarifRenderer.setWriter(new FileWriter("report.sarif"));
            analysis.addRenderer(sarifRenderer);
            
            // CSV renderer for spreadsheet analysis
            CSVRenderer csvRenderer = new CSVRenderer();
            csvRenderer.setWriter(new FileWriter("report.csv"));
            analysis.addRenderer(csvRenderer);
            
            setupAndRunAnalysis(analysis);
        }
    }
    
    public void demonstrateIDERenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // Emacs integration
            EmacsRenderer emacsRenderer = new EmacsRenderer();
            emacsRenderer.setWriter(new FileWriter("emacs-report.txt"));
            analysis.addRenderer(emacsRenderer);
            
            // IntelliJ IDEA integration
            IDEAJRenderer ideaRenderer = new IDEAJRenderer();
            ideaRenderer.setWriter(new FileWriter("idea-report.txt"));
            analysis.addRenderer(ideaRenderer);
            
            setupAndRunAnalysis(analysis);
        }
    }
    
    public void demonstrateSpecialRenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // Empty renderer for silent mode (no output)
            EmptyRenderer silentRenderer = new EmptyRenderer();
            analysis.addRenderer(silentRenderer);
            
            // Code Climate renderer for CI/CD
            CodeClimateRenderer ccRenderer = new CodeClimateRenderer();
            ccRenderer.setWriter(new FileWriter("codeclimate.json"));
            analysis.addRenderer(ccRenderer);
            
            setupAndRunAnalysis(analysis);
        }
    }
    
    private void setupAndRunAnalysis(PmdAnalysis analysis) throws IOException {
        analysis.files().addDirectory(Paths.get("src/main/java"));
        
        RuleSetLoader loader = analysis.newRuleSetLoader();
        analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
        
        analysis.performAnalysis();
    }
}

Custom Renderer Implementation

Framework for implementing custom renderers with specific formatting requirements.

/**
 * Abstract base class for implementing custom renderers.
 * Provides common functionality and lifecycle management.
 */
abstract class AbstractRenderer implements Renderer {
    
    /**
     * Constructor with renderer name
     * @param name Unique name for the renderer
     */
    protected AbstractRenderer(String name);
    
    /**
     * Constructor with name and description
     * @param name Unique name for the renderer
     * @param description Human-readable description
     */
    protected AbstractRenderer(String name, String description);
    
    /**
     * Get output writer
     * @return Writer for formatted output
     */
    protected Writer getWriter();
    
    /**
     * Write string to output
     * @param str String to write
     */
    protected void write(String str) throws IOException;
    
    /**
     * Write formatted string to output
     * @param format Format string
     * @param args Format arguments
     */
    protected void writef(String format, Object... args) throws IOException;
    
    /**
     * Write line to output
     * @param line Line to write (newline added automatically)
     */
    protected void writeln(String line) throws IOException;
    
    /**
     * Render single rule violation (template method)
     * @param violation RuleViolation to render
     */
    protected abstract void renderViolation(RuleViolation violation) throws IOException;
    
    /**
     * Render processing error (template method)  
     * @param error ProcessingError to render
     */
    protected void renderError(Report.ProcessingError error) throws IOException;
    
    /**
     * Render configuration error (template method)
     * @param error ConfigurationError to render  
     */
    protected void renderConfigError(Report.ConfigurationError error) throws IOException;
}

Usage Examples:

import net.sourceforge.pmd.renderers.AbstractRenderer;
import net.sourceforge.pmd.reporting.*;
import java.io.IOException;

// Custom renderer implementation
public class CustomJSONRenderer extends AbstractRenderer {
    
    private boolean firstViolation = true;
    private int violationCount = 0;
    
    public CustomJSONRenderer() {
        super("custom-json", "Custom JSON renderer with extra metadata");
    }
    
    @Override
    public String defaultFileExtension() {
        return "json";
    }
    
    @Override
    public void start() throws IOException {
        writeln("{");
        writeln("  \"tool\": \"PMD\",");
        writef("  \"version\": \"%s\",%n", PMDVersion.VERSION);
        writef("  \"timestamp\": \"%s\",%n", new Date());
        writeln("  \"violations\": [");
        firstViolation = true;
        violationCount = 0;
    }
    
    @Override
    protected void renderViolation(RuleViolation violation) throws IOException {
        if (!firstViolation) {
            writeln(",");
        }
        firstViolation = false;
        violationCount++;
        
        writeln("    {");
        writef("      \"file\": \"%s\",%n", escapeJson(violation.getFilename()));
        writef("      \"line\": %d,%n", violation.getBeginLine());
        writef("      \"column\": %d,%n", violation.getBeginColumn());
        writef("      \"endLine\": %d,%n", violation.getEndLine());
        writef("      \"endColumn\": %d,%n", violation.getEndColumn());
        writef("      \"rule\": \"%s\",%n", escapeJson(violation.getRule().getName()));
        writef("      \"priority\": \"%s\",%n", violation.getRule().getPriority().getName());
        writef("      \"message\": \"%s\",%n", escapeJson(violation.getDescription()));
        
        // Add extra metadata
        if (!violation.getPackageName().isEmpty()) {
            writef("      \"package\": \"%s\",%n", escapeJson(violation.getPackageName()));
        }
        if (!violation.getClassName().isEmpty()) {
            writef("      \"class\": \"%s\",%n", escapeJson(violation.getClassName()));
        }
        if (!violation.getMethodName().isEmpty()) {
            writef("      \"method\": \"%s\",%n", escapeJson(violation.getMethodName()));
        }
        
        writef("      \"suppressed\": %b%n", violation.isSuppressed());
        write("    }");
    }
    
    @Override
    protected void renderError(Report.ProcessingError error) throws IOException {
        // Add errors to separate section if needed
        writef("    // Processing error in %s: %s%n", 
            error.getFile(), error.getMessage());
    }
    
    @Override
    public void end() throws IOException {
        writeln();
        writeln("  ],");
        writef("  \"summary\": {%n");
        writef("    \"violationCount\": %d%n", violationCount);
        writeln("  }");
        writeln("}");
        flush();
    }
    
    private String escapeJson(String str) {
        if (str == null) return "null";
        return str.replace("\\", "\\\\")
                 .replace("\"", "\\\"")
                 .replace("\n", "\\n")
                 .replace("\r", "\\r")
                 .replace("\t", "\\t");
    }
}

// Custom renderer with properties
public class CustomHTMLRenderer extends AbstractRenderer {
    
    private static final PropertyDescriptor<String> TITLE_PROPERTY = 
        PropertyFactory.stringProperty("title")
            .desc("HTML report title")
            .defaultValue("PMD Analysis Report")
            .build();
    
    private static final PropertyDescriptor<String> CSS_URL_PROPERTY = 
        PropertyFactory.stringProperty("cssUrl")
            .desc("URL to external CSS file")
            .defaultValue("")
            .build();
    
    public CustomHTMLRenderer() {
        super("custom-html", "Custom HTML renderer with styling options");
        definePropertyDescriptor(TITLE_PROPERTY);
        definePropertyDescriptor(CSS_URL_PROPERTY);
    }
    
    @Override
    public String defaultFileExtension() {
        return "html";
    }
    
    @Override
    public void start() throws IOException {
        String title = getProperty(TITLE_PROPERTY);
        String cssUrl = getProperty(CSS_URL_PROPERTY);
        
        writeln("<!DOCTYPE html>");
        writeln("<html>");
        writeln("<head>");
        writef("  <title>%s</title>%n", escapeHtml(title));
        writeln("  <meta charset=\"UTF-8\">");
        
        if (!cssUrl.isEmpty()) {
            writef("  <link rel=\"stylesheet\" href=\"%s\">%n", escapeHtml(cssUrl));
        } else {
            writeDefaultCSS();
        }
        
        writeln("</head>");
        writeln("<body>");
        writef("  <h1>%s</h1>%n", escapeHtml(title));
        writeln("  <table class=\"violations\">");
        writeln("    <thead>");
        writeln("      <tr>");
        writeln("        <th>File</th>");
        writeln("        <th>Line</th>");
        writeln("        <th>Rule</th>");
        writeln("        <th>Priority</th>");
        writeln("        <th>Message</th>");
        writeln("      </tr>");
        writeln("    </thead>");
        writeln("    <tbody>");
    }
    
    @Override
    protected void renderViolation(RuleViolation violation) throws IOException {
        writeln("      <tr class=\"violation\">");
        writef("        <td>%s</td>%n", escapeHtml(violation.getFilename()));
        writef("        <td>%d</td>%n", violation.getBeginLine());
        writef("        <td>%s</td>%n", escapeHtml(violation.getRule().getName()));
        writef("        <td class=\"priority-%s\">%s</td>%n", 
            violation.getRule().getPriority().name().toLowerCase(),
            violation.getRule().getPriority().getName());
        writef("        <td>%s</td>%n", escapeHtml(violation.getDescription()));
        writeln("      </tr>");
    }
    
    @Override
    public void end() throws IOException {
        writeln("    </tbody>");
        writeln("  </table>");
        writeln("</body>");
        writeln("</html>");
        flush();
    }
    
    private void writeDefaultCSS() throws IOException {
        writeln("  <style>");
        writeln("    body { font-family: Arial, sans-serif; margin: 20px; }");
        writeln("    table { border-collapse: collapse; width: 100%; }");
        writeln("    th, td { border: 1px solid #ddd; padding: 8px; text-align: left; }");
        writeln("    th { background-color: #f2f2f2; }");
        writeln("    .priority-high { color: #d32f2f; font-weight: bold; }");
        writeln("    .priority-medium { color: #f57c00; }");
        writeln("    .priority-low { color: #388e3c; }");
        writeln("  </style>");
    }
    
    private String escapeHtml(String str) {
        if (str == null) return "";
        return str.replace("&", "&amp;")
                 .replace("<", "&lt;")
                 .replace(">", "&gt;")
                 .replace("\"", "&quot;")
                 .replace("'", "&#x27;");
    }
}

// Using custom renderers
public class CustomRendererUsage {
    
    public void useCustomRenderers() throws IOException {
        PMDConfiguration config = new PMDConfiguration();
        
        try (PmdAnalysis analysis = PmdAnalysis.create(config)) {
            // Use custom JSON renderer
            CustomJSONRenderer jsonRenderer = new CustomJSONRenderer();
            jsonRenderer.setWriter(new FileWriter("custom-report.json"));
            analysis.addRenderer(jsonRenderer);
            
            // Use custom HTML renderer with properties
            CustomHTMLRenderer htmlRenderer = new CustomHTMLRenderer();
            htmlRenderer.setProperty(htmlRenderer.TITLE_PROPERTY, "My Project Analysis");
            htmlRenderer.setProperty(htmlRenderer.CSS_URL_PROPERTY, "styles/pmd-report.css");
            htmlRenderer.setWriter(new FileWriter("custom-report.html"));
            analysis.addRenderer(htmlRenderer);
            
            // Configure analysis and run
            analysis.files().addDirectory(Paths.get("src"));
            RuleSetLoader loader = analysis.newRuleSetLoader();
            analysis.addRuleSet(loader.loadFromResource("rulesets/java/quickstart.xml"));
            
            analysis.performAnalysis();
        }
    }
}

Types

/**
 * Factory for creating built-in renderers by name
 */
final class RendererFactory {
    
    /**
     * Create renderer by name
     * @param name Renderer name (xml, html, text, json, etc.)
     * @param properties Optional properties for configuration
     * @return Renderer instance
     */
    static Renderer createRenderer(String name, Properties properties);
    
    /**
     * Get all available renderer names
     * @return Set of supported renderer names
     */
    static Set<String> getAvailableRenderers();
    
    /**
     * Check if renderer name is supported
     * @param name Renderer name to check
     * @return true if renderer is available
     */
    static boolean isRendererAvailable(String name);
}

/**
 * Configuration for file name rendering in reports
 */
interface ConfigurableFileNameRenderer {
    
    /**
     * Get display name for file
     * @param fileId File identifier
     * @return Formatted display name
     */
    String getDisplayName(FileId fileId);
    
    /**
     * Set root paths for relativizing file names
     * @param roots List of root paths for making relative paths
     */
    void setRelativizeRoots(List<Path> roots);
    
    /**
     * Add root path for relativizing
     * @param root Root path to add
     */
    void addRelativizeRoot(Path root);
}

/**
 * Renderer properties for customization
 */
interface RendererProperties {
    
    /**
     * Set string property
     * @param name Property name
     * @param value Property value
     */
    void setProperty(String name, String value);
    
    /**
     * Get string property with default
     * @param name Property name
     * @param defaultValue Default if not set
     * @return Property value or default
     */
    String getProperty(String name, String defaultValue);
    
    /**
     * Set boolean property
     * @param name Property name
     * @param value Property value
     */
    void setBooleanProperty(String name, boolean value);
    
    /**
     * Get boolean property with default
     * @param name Property name
     * @param defaultValue Default if not set
     * @return Property value or default
     */
    boolean getBooleanProperty(String name, boolean defaultValue);
}

Now I'll complete the todo list:

<function_calls> <invoke name="TodoWrite"> <parameter name="todos">[{"content": "Create tile.json manifest for PMD Core Knowledge Tile", "status": "completed", "activeForm": "Creating tile.json manifest"}, {"content": "Create entry-point documentation at docs/index.md with overview and capabilities", "status": "completed", "activeForm": "Creating entry-point documentation"}, {"content": "Create Core PMD Analysis sub-doc for PmdAnalysis and PMDConfiguration", "status": "completed", "activeForm": "Creating Core PMD Analysis sub-doc"}, {"content": "Create Rule System sub-doc for Rule, RuleSet, RulePriority APIs", "status": "completed", "activeForm": "Creating Rule System sub-doc"}, {"content": "Create Language Framework sub-doc for Language, LanguageRegistry APIs", "status": "completed", "activeForm": "Creating Language Framework sub-doc"}, {"content": "Create AST Processing sub-doc for Node and AST navigation APIs", "status": "completed", "activeForm": "Creating AST Processing sub-doc"}, {"content": "Create Reporting System sub-doc for Report, RuleViolation, listeners", "status": "completed", "activeForm": "Creating Reporting System sub-doc"}, {"content": "Create Properties System sub-doc for PropertySource, PropertyDescriptor APIs", "status": "completed", "activeForm": "Creating Properties System sub-doc"}, {"content": "Create Copy-Paste Detection sub-doc for CPD functionality", "status": "completed", "activeForm": "Creating Copy-Paste Detection sub-doc"}, {"content": "Create Utilities and Support Classes sub-doc for utility APIs", "status": "completed", "activeForm": "Creating Utilities sub-doc"}]

Install with Tessl CLI

npx tessl i tessl/maven-net-sourceforge-pmd--pmd-core

docs

ast-processing.md

copy-paste-detection.md

core-analysis.md

index.md

language-framework.md

properties-system.md

rendering-system.md

reporting-system.md

rule-system.md

utilities.md

tile.json