Movatterモバイル変換


[0]ホーム

URL:


 
» ADR 3 - API evolution principles Edit on GitHub

ADR 3 - API evolution principles

Table of Contents

Context

The API of PMD has been growing over the years and needed some cleanup. The goal is, tohave a clear separation between a well-defined API and the implementation, which is internal.This should help us in future development.

Until PMD 7.0.0, all released public members and types were implicitly considered partof public PMD API, including inheritance-specific members (protected members, abstract methods).We have maintained those APIs with the goal to preserve full binary compatibility between minor releases,only breaking those APIs infrequently, for major releases.

PMD is used and integrated in many different tools such as IDE plugins or build plugins. These pluginsuse our public API and rely on it being stable, hence we tried to break it only infrequently.

In order to allow PMD to move forward at a faster pace, this implicit contract willbe invalidated with PMD 7.0.0 and onwards. We now introduce more fine-grained distinctions betweenthe type of compatibility support we guarantee for our libraries, and ways to makethem explicit to clients of PMD.

The actual API development and marking some part of the API as internal or add new API is an ongoing task,that will need to be done everytime. We won’t just define an API and then are done with it.The API will change as new features want to be implemented.

This decision document aims to document principles and guidelines that are used for PMD development.

Decision

Semantic Versioning

PMD and all its modules are versioned together. PMD usesSemantic Versioning 2.0.0.This means, that each PMD version consists of MAJOR.MINOR.PATCH components:

  • MAJOR version is incremented for incompatible API changes
  • MINOR version is incremented for added functionality in a backwards compatible way
  • PATCH version is incremented for backward compatible bug fixes

Additional labels for release candidates might be used.

Incompatible API changes shouldn’t be introduced lightly. SeeFAQ: If even the tiniest backward incompatible changes to the public API require a major version bump, won’t I end up at version 42.0.0 very rapidly?.

Project structure and Java base packages names

PMD is mainly developed in the Java programming language. The build tool is Maven and the PMD build consistsof several maven modules.

  • All packages belonging to a given module should have a common package prefix.
  • Given a package name, it should be easy to figure out to which module this package belongs. There is a 1:1 mappingbetween maven module and package. This rule helps to find the source code for any fully qualified (Java) class name.
  • Two modules must not define the same packages. That means, it is not allowed that any given package spans more thanone module. Otherwise, the mapping between module and package wouldn’t be unambiguous.
  • The base package for all PMD source code isnet.sourceforge.pmd. There are many different sub packages.
  • The core modulepmd-core uses directly the base package as the only module. All other modules must usespecific sub packages.
  • Language modules use the base packagenet.sourceforge.pmd.lang.<language id>.E.g.pmd-java uses the packagenet.sourceforge.pmd.lang.java.
  • All other modules use the base packagenet.sourceforge.pmd.<module>,E.g.pmd-cli uses the packagenet.sourceforge.pmd.cli.

Criteria for public API

Public API is

  • API needed to execute PMD analysis
    • Renderers
    • RuleSet XML Schema
    • Configuration
    • Ant Tasks
  • API needed to implement custom rules
    • AST structure and classes of languages (incl. AST structure for XPath rules)
    • XPath functions
    • Language Symbol Table / Metrics / Type Resolution (Not the implementation)

Not public API is

  • Anything in packagesinternal andimpl
  • Inheritance-specific members of AST related classes and interfaces. E.g. adding a member to aninterface shouldn’t be considered API breaking
  • Setters in AST classes are private. They are only used in the parser.

Separation between public API, internal and implementation

All packages are considered to be public API by default, withtwo exceptions:

  • Any package that contains aninternal segment is considered internal. E.g.net.sourceforge.pmd.internal.Internal API is meant for useonly by the main PMD codebase. Internal types and methodsmay be modified in any way, or even removed, at any time without a MAJOR version change.

    The@InternalApi annotation will be used for types that have to live outside ofthese packages, e.g. methods of a public type that shouldn’t be used outside PMD (again,these can be removed anytime).The javadoc tag@internalApi None of this is published API, and compatibility can be broken anytime! Use this only at your own risk.will be added additionally.

  • Any package that contains animpl segment is considered internal. E.g.net.sourceforge.pmd.lang.impl.These packages contain base classes that are needed for extending PMD (like adding a new language).These can change at any time without a MAJOR version change.

    In a later version, theimpl packages could be promoted as a public API for implementing newlanguages for PMD outside the main monorepo. In that sense, e.g. the modulepmd-java is allowedto depend onimpl packages ofpmd-core, but ideally it doesn’t depend oninternal packages ofpmd-core (or any other module). However, for now, theimpl packages areexplicitly consideredinternal until this decision is revised.

Deprecation and removing of old APIs

  • APIs can be deprecated at any time (even in PATCH versions). Deprecated APIs are marked with the@Deprecated annotation.The javadoc tag@deprecated Since x.y.z. Description will be added additionally.
  • Deprecations should be listed in the release notes.
  • Deprecated APIs can only be removed with a MAJOR version change.

Experimental APIs

  • New features often introduce new APIs. These new APIs can be marked with the annotation@Experimental atthe class or method level.These new APIs should use the javadoc tags@since x.y.z and@experimental Description.
  • APIs marked with the@Experimental annotation are subject to change and are considerednot stable.They can be modified in any way, or even removed, at any time. You should not use or relyon them in any production code. They are purely to allow broad testing and feedback.
  • Experimental APIs can be introduced or removed with at least a MINOR version change.These experimental APIs should be listed in the release notes.
  • Experimental APIs can be promoted to Public APIs with at least a MINOR version change.

Guidelines for AST classes

AST classes of the individual language modules are used by custom rule implementations and are consideredPublic API in general. Rules only read the AST and do not need to modify it.

In order to minimize the public API surface of AST classes, the following guidelines apply:

  • Concrete AST classes should be final, to avoid custom subclasses.
  • Concrete AST classes should only have a package private constructor to avoid manual instantiation.Only the parser of the language (which lives in the same package) should be able to create new instancesof AST classes.
  • Concrete AST classes should not have public setters. All setters should be package private, so thatonly the parser of the language can call the setters during AST construction.

Non-concrete AST classes (like base classes or common interfaces) should follow similar guidelines:

  • Only package private constructor
  • Only package private setters

Summary of the annotations

  • @InternalApi (net.sourceforge.pmd.annotation.InternalApi)

    This annotation is used for API members that are not publicly supported API but have to live inpublic packages (outsideinternal packages).Such members may be removed, renamed, moved, or otherwise broken at any time and should not berelied upon outside the main PMD codebase.

  • @Experimental (net.sourceforge.pmd.annotation.Experimental)

    API members marked with the@Experimental annotation at the class or method level are subject to change.It is an indication that the feature is in experimental, unstable state.The API members can be modified in any way, or even removed, at any time, without warning.You should not use or rely on them in any production code. They are purely to allow broad testing and feedback.

  • @Deprecated (java.lang.Deprecated)

    API members marked with the@Deprecated annotation at the class or method level will remain supporteduntil the next major release, but it is recommended to stop using them. These members might beremoved with the next MAJOR release.

Status

Accepted (Last updated: January 2026 (7.21.0))

Consequences

  • Clearly defining the API PMD provides will help to further modularize PMD using theJavaModule System.
  • Simpler decisions when to increase MAJOR, MINOR of PATCH version.
  • Refactoring of the implementation is possible without affecting public API.

Change History

2026-01-29: Added details on how to use javadoc tags for deprecated, experimental and internal APIs. (#6392)

2024-02-01: Changed status to “Accepted”. (#4756)

2023-12-01: Proposed initial version.


This documentation is written in markdown.
If there is something missing or can be improved, edit this page on github and create a PR: Edit on GitHub

©2026 PMD Open Source Project. All rights reserved.
Page last updated: January 2026 (7.21.0)
Site last generated: Jan 30, 2026

PMD                logo


[8]ページ先頭

©2009-2026 Movatter.jp