Table of Contents

29-May-2026 - 7.25.0-SNAPSHOT

The PMD team is pleased to announce PMD 7.25.0-SNAPSHOT.

This is a minor release.

🚀️ New and noteworthy

Updated ANTLR library to 4.13.2

We have updated the ANTLR library (parser generator) from 4.9.3 to the latest version 4.13.2, in order to be able to use the latest version of Apex parser library.

This is an incompatible update: In case you use custom language modules based on ANTLR, you need to make sure to regenerate all of your lexers and parsers with the new ANTLR version.

For the ANTLR based language modules, that PMD ships (kotlin and swift and various CPD modules), this is already done.

🌟️ New and Changed Rules

New Rules

  • The new Java rule JUnit5TestNoPrivateModifier find JUnit test classes and methods that are private. Test classes, test methods, and lifecycle methods are not required to be public, but they must not be private. Otherwise, they won’t be found by the test framework.
  • The new Java rule UnnecessaryBlock reports blocks that are unnecessary as they don’t introduce a new scope. This rule helps simplify code structure by identifying and flagging redundant blocks that can make code harder to read and may be misleading.
  • The new Java rule VariableDeclarationUsageDistance flags local variables that are declared far from their usage, which can make code harder to read. The rule has a property maxDistance that allows to configure the maximum allowed distance between declaration and usage.
  • The new Java rule AssertStatementInTest detects usages of assert statement in tests. These should be replaced by framework assertion methods such as assertEquals. Such methods provide better error messages and make test behave correctly when running without -ea.

Changed Rules

🐛️ Fixed Issues

  • core
    • #4972: [core] Update ANTLR to 4.13.2
    • #6308: [core] CPD Markdown format: Add syntax highlighting
  • java
    • #5721: [java] StackOverflowError in 7.17.0 with nested wildcard generics
    • #5746: [java] Separate test sources and resources
    • #6688: [java] LocalVariableCouldBeFinalRule API changed
  • java-bestpractices
    • #3212: [java] Enhance UseStandardCharsets to flag some constructors of IO-related classes
    • #3777: [java] New rule: AssertStatementInTest
    • #5477: [java] JUnit5TestShouldBePackagePrivate is not applied when @Test method is only present in parent class
    • #6606: [java] UnusedPrivateField: False positive on JUnit Jupiter @FieldSource
  • java-codestyle
    • #2801: [java] OnlyOneReturn should have a property to allow early exits (guard clauses)
    • #6427: [java] UnnecessaryCast: False positive for long cast before bit-shift operations on int/byte
    • #6602: [java] LocalVariableCouldBeFinal: False negative when multiple variables are declared at once
    • #6622: [java] New rule: UnnecessaryBlock
    • #6640: [java] New rule: VariableDeclarationUsageDistance
  • java-design
    • #559: [java] UseUtilityClass: False negative for constant only classes
  • java-errorprone
    • #3288: [java] New Rule: JUnit5TestNoPrivateModifier
    • #4288: [java] Document that CallSuperFirst/CallSuperLast are Android specific
    • #6163: [java] ConstructorCallsOverridableMethod: False positive when method is from enclosing class
    • #6517: [java] UselessPureMethodCall: False negative for methods on IntStream/LongStream/DoubleStream
    • #6652: [java] AvoidInstanceofChecksInCatchClause: false negative when pattern-matching instanceof
  • java-multithreading
    • #6520: [java] DoNotUseThreads: False positive on legitimate java.lang.Thread.onSpinWait() call
    • #6636: [java] OverridingThreadRun: Fix false negatives with other methods and anonymous classes
  • kotlin
    • #6608: [kotlin] Lexer or parse errors are reported to stderr only without file context
    • #6648: [kotlin] Multi-dollar interpolation parse error in annotations

🚨️ API Changes

✨️ Merged pull requests

  • #6084: [java] Shrink reported locations for some rules - UncleOwen (@UncleOwen)
  • #6522: [java] Fix #6520: DoNotUseThreads: fix false positive on Thread.onSpinWait() - leemeii (@leemeii)
  • #6524: [java] Fix #6517: UselessPureMethodCall: fix false negative for primitive streams - leemeii (@leemeii)
  • #6553: [java] Fix StackOverflowError in TypeOps projection of cyclic captured type vars - Sebastian Lövdahl (@slovdahl)
  • #6557: [java] New rule: AssertStatementInTest - Zbynek Konecny (@zbynek)
  • #6561: [java] Fix #6163: ConstructorCallsOverridableMethod: False positive with call to enclosing class - Lukas Gräf (@lukasgraef)
  • #6573: [java] Fix #6427: Add bitwise and/or/xor to BINARY_PROMOTED_OPS - UncleOwen (@UncleOwen)
  • #6587: [java] Fix #2801: Add a property to OnlyOneReturnRule to allow guard ifs - UncleOwen (@UncleOwen)
  • #6597: [java] Fix #3212: Enhance UseStandardCharsets - UncleOwen (@UncleOwen)
  • #6601: [java] Fix #4288: Document that CallSuperFirst and CallSuperLast are android only - UncleOwen (@UncleOwen)
  • #6603: [java] Fix #6602: Fix false negative in LocalVariableCouldBeFinalRule - UncleOwen (@UncleOwen)
  • #6604: [java] Fix #3288: New rule JUnit5TestNoPrivateModifierRule - UncleOwen (@UncleOwen)
  • #6605: [java] Fix #6308: Add syntax highlighting to MarkdownRenderer - UncleOwen (@UncleOwen)
  • #6619: [java] Fix #5746: Separate test sources and resources - UncleOwen (@UncleOwen)
  • #6621: [core] Fix #4972: Update ANTLR from 4.9.3 to 4.13.2 - UncleOwen (@UncleOwen)
  • #6623: [java] Cleanup: Remove TODO from ModifierOwner.getVisibility() - UncleOwen (@UncleOwen)
  • #6636: [java] OverridingThreadRun: Fix false negatives with other methods and anonymous classes - Zbynek Konecny (@zbynek)
  • #6638: [java] Fix #559: Improve UseUtilityClassRule to trigger also on static members - UncleOwen (@UncleOwen)
  • #6639: [java] New rule: UnnecessaryBlock - UncleOwen (@UncleOwen)
  • #6640: [java] New rule: VariableDeclarationUsageDistance - Zbynek Konecny (@zbynek)
  • #6646: [test] Split up AbstractRuleSetFactoryTest.testAllPMDBuiltInRulesMeetConventions() - UncleOwen (@UncleOwen)
  • #6650: [kotlin] Fix #6608: Improve kotlin parser error handling - Peter Paul Bakker (@stokpop)
  • #6653: [kotlin] Fix #6648: Multi-dollar interpolation for regular strings - Peter Paul Bakker (@stokpop)
  • #6654: [swift] Fix invalid swift token OSXApplicationExtension - Andreas Dangel (@adangel)
  • #6658: [doc] Fix capitalization of ANTLR in release notes - Zbynek Konecny (@zbynek)
  • #6661: [java] Fix #6652: Support new-style instanceof (with pattern matching) in AvoidInstanceofChecksInCatchClause - UncleOwen (@UncleOwen)
  • #6680: [java] Fix #5477: JUnit5TestShouldBePackagePrivate is not applied when @Test method is only present in parent class - UncleOwen (@UncleOwen)

📦️ Dependency updates

📈️ Stats