github pmd/pmd pmd_releases/7.27.0
PMD 7.27.0 (28-August-2026)

3 hours ago

28-August-2026 - 7.27.0

The PMD team is pleased to announce PMD 7.27.0.

This is a minor release.

Table Of Contents

  • 🚀️ New and noteworthy
    • Java 27 Support
    • Updated Apex Support
    • Kotlin type-aware analysis
  • 🌟️ New and Changed Rules
    • New Rules
    • Renamed Rules
    • Changed Rules
    • Deprecated Rules
  • 🐛️ Fixed Issues
  • 🚨️ API Changes
    • Deprecations
    • Experimental API
  • ✨️ Merged pull requests
  • 📦️ Dependency updates
  • 📈️ Stats

🚀️ New and noteworthy

Java 27 Support

This release of PMD brings support for Java 27.

There are no new standard language features.

There is one preview language feature:

In order to analyze a project with PMD that uses these preview language features,
you'll need to select the new language version 27-preview:

pmd check --use-version java-27-preview ...

Note: Support for Java 25 preview language features have been removed. The version "25-preview"
is no longer available.

Updated Apex Support

The Apex language support has been bumped to version 67.0 (Summer '26). It supports the new
Multiline String literals.

Kotlin type-aware analysis

Kotlin now supports type-aware analysis via the auxClasspath language property (see #6677).
Resolved type names, return types, and annotation FQNs are available through
KotlinNodeTypeData for use in Java-based rules.

Note: Type data is not yet accessible in XPath rules or the PMD Rule Designer. This will be added in the next version.

🌟️ New and Changed Rules

New Rules

  • The new java rule UnusedReturnValue (Java Error Prone) finds method calls whose result is not used,
    although ignoring the result of these method calls is likely a mistake.
    The rule is referenced in the quickstart.xml ruleset for Java.
  • New rule ProtectedMemberInFinalClass (Java Design) finds protected members defined in final classes.
    Such members should use package or private visibility to clarify their intended scope.
    The rule replaces now deprecated rules AvoidProtectedFieldInFinalClass and AvoidProtectedMethodInFinalClassNotExtending
    and flags members that were previously not detected by either of these rules, such as nested types or constructors.
    The rule is referenced in the quickstart.xml ruleset for Java.

Renamed Rules

  • The rule InstantiableUtilityClass (Java Design) was renamed from UseUtilityClass to better reflect the problem.
    The old name still works but is deprecated.

Changed Rules

  • The rule CommentRequired (Java Documentation)
    has a new property packageMethodCommentRequirement. It controls whether Javadoc comments are required (or
    unwanted) for package-private methods and constructors. Previously, only public and protected methods could
    be configured (via publicMethodCommentRequirement and protectedMethodCommentRequirement). The new property
    defaults to Ignored, so existing rule configurations are unaffected.
    This was implemented in #6880.
  • The rule BooleanGetMethodName (Java Codestyle) has a new property
    includeWrappedType. If set to true (default), the rule treats Boolean and boolean identical.
    If set to false, the rule follows the bean convention and treats Boolean like any other object.

Deprecated Rules

🐛️ Fixed Issues

  • apex
    • #6478: [apex] Parser error when using CALENDAR_YEAR() in SOQL
    • #6887: [apex] ParseException on Summer '26 multiline string literals ('''...''')
  • apex-bestpractices
    • #5904: [apex] ApexUnitTestShouldNotUseSeeAllDataTrue violation range should only be the annotation and not the entire test method
  • java
    • #5041: [java] Parsing failed in ParseLock#doParse(): IndexOutOfBoundsException
    • #6010: [java] java.lang.OutOfMemoryError: Java heap space when accessing big Jar files with PMD 7
    • #6374: [java] Support Java 27
    • #6768: [java] Disambiguation IllegalStateException resolving a synthesized record accessor used as a call argument alongside an anonymous class
    • #6932: [java] AssertionError when outer class is parsed before inner class with conflicting visibility
  • java-bestpractices
    • #1237: [java] AbstractClassWithoutAnyMethod: False positive for empty subclasses that inherit methods
    • #1287: [java] GuardLogStatement: False positive when using negative guard conditions
    • #2033: [jsp] NoClassAttribute: False positive for jsp:useBean
    • #5514: [java] ExhaustiveSwitchHasDefault: False positive for non-exhaustive switch statements
    • #5670: [java] ExhaustiveSwitchHasDefault: False positive with final fields not initialized in constructor
    • #6200: [java] UnusedAssignment: False positive about the ++ unary operator
    • #6393: [java] UnusedPrivateMethod: False positive with overloaded private methods called with values returned from methods of an unresolved type
    • #6611: [java] UnnecessaryVarargsArrayCreation: False positive when removing the array creates overload ambiguity
    • #6965: [java] AbstractClassWithoutAnyMethod: False Positive on derived abstract class
  • java-codestyle
    • #2974: [java] Merge rules about protected in final class (AvoidProtectedFieldInFinalClass, AvoidProtectedMethodInFinalClassNotExtending)
    • #5441: [java] UseDiamondOperator: False positive with interdependent generic vars
    • #6958: [java] BooleanGetMethodName should have the option to treat boolean wrapper type differently
    • #6274: [java] UselessParentheses: False positive in ternary else expression
    • #6651: [java] UnnecessaryImport: False positive when Javadoc {@link} references an array type
    • #6709: [java] LambdaCanBeMethodReference: False positive with array creation containing constructor call in receiver
    • #6737: [java] TooManyStaticImports: @SuppressWarnings("PMD.TooManyStaticImports") has stopped working
    • #6846: [java] VariableDeclarationUsageDistance: False positive with variables grouped at the top of a block
    • #6867: [java] UnnecessaryFullyQualifiedName: ContextedAssertionError: This should be unreachable: unknown constant ScopeInfo: MODULE_IMPORT
    • #6943: [java] UnnecessaryCast: False positives related to generics
  • java-design
    • #6714: [java] Rename UseUtilityClass to InstantiableUtilityClass
    • #6844: [java] AvoidThrowingNewInstanceOfSameException: message inconsistent with logic
    • #6881: [java] CognitiveComplexity does not count switch expressions
    • #6925: [java] ImmutableField: False positive on picocli annotated fields
  • java-documentation
    • #6270: [java] CommentSize: False positive with file header comments
    • #6880: [java] CommentRequired: add packageMethodCommentRequirement property
  • java-errorprone
    • #2840: [java] CloseResource: False positive on mocks
    • #3880: [java] ReturnEmptyCollectionRatherThanNull: False negative when a null value is assigned to a local that is later returned
    • #4623: [java] CloseResource: False positive with resource being closed in method
    • #6435: [java] UnconditionalIfStatement: False negative for negated boolean constant
    • #6537: [java] StaticEJBFieldShouldBeFinal: False Negative when using @stateless etc.
    • #6547: [java] NonSerializableClass: False negative for generic element/value types of collections and maps
    • #6625: [java] New rule: UnusedReturnValue
    • #6695: [java] ReturnEmptyCollectionRatherThanNull: False negative when null is returned through a local variable
    • #6742: [java] CloseResource: False positive when a correctly-closed resource is declared without initializer
    • #6744: [java] ReturnEmptyCollectionRatherThanNull: False negatives when a returned expression can evaluate to null
    • #6826: [java] AssertEqualsArgumentOrder: False positive for double assertEquals
    • #6900: [java] DoubleCheckedLocking: False negative when the outer null check is written as !(x != null)
  • java-multithreading
    • #6747: [java] NonThreadSafeSingleton: False negative with ternary conditional operator
  • kotlin
    • #6795: [kotlin] Add kotlin-type-mapper infrastructure
    • #6891: [kotlin] AnnotationFqnAnnotator: @TypeName not set on UnescapedAnnotation nodes
  • miscellaneous
    • #1995: [core] PMD should display number of rules violated or errors found
    • #2527: [doc] CPD: Invalid link to String Tiling Algorithm
    • #4952: [doc] Improve doc around PMDConfiguration#prependAuxclasspath #setClassloader
    • #4953: [core] Deprecate PMDConfiguration#setClassloader and #getClassloader
    • #6837: [ci] chore: actions/create-github-app-token: Input 'app-id' has been deprecated with message: Use 'client-id' instead
    • #6865: [core] Include the running PMD version in the "Unable to find referenced rule" error
    • #6913: [core] RuleSetLoader#loadFromString ignores previously configured Resource/ClassLoader
    • #6952: [core] Ruleset references are not resolved relative to the referencing ruleset

🚨️ API Changes

Deprecations

Experimental API

  • core
    • The new AuxClasspathLoader is a replacement for the deprecated ClasspathClassLoader.
      It deals with a typical classpath to load classes need for Java's type resolution. It has the static method
      enableReuse(int) which enables caching of AuxClasspathLoader instances. This is useful for unit tests
      or IDE plugins, when PMD is executed multiple times within one JVM instance. Don't forget to call
      disableReuse() when you're done to close all cached instances.
  • kotlin
    • KotlinNodeTypeData: Provides the initial API to access type information
      on Kotlin AST nodes. It's part of the new Kotlin type-aware analysis.

✨️ Merged pull requests

📦️ Dependency updates

  • #6824: Bump PMD from 7.25.0 to 7.26.0
  • #6830: chore(deps): bump actions/setup-java from 5.3.0 to 5.4.0
  • #6831: chore(deps): bump junit.version from 6.1.0 to 6.1.1
  • #6832: chore(deps): bump actions/cache from 6.0.0 to 6.1.0
  • #6833: chore(deps): bump actions/cache/restore from 6.0.0 to 6.1.0
  • #6834: chore(deps): bump ruby/setup-ruby from 1.314.0 to 1.315.0
  • #6835: chore(deps): bump crate-ci/typos from 1.47.2 to 1.48.0
  • #6836: chore(deps): bump com.puppycrawl.tools:checkstyle from 13.6.0 to 13.7.0
  • #6847: chore(deps): bump marocchino/sticky-pull-request-comment from 3.0.4 to 3.0.5
  • #6848: chore(deps): bump actions/setup-java from 5.4.0 to 5.5.0
  • #6849: chore(deps): bump ruby/setup-ruby from 1.315.0 to 1.316.0
  • #6850: chore(deps): bump scalameta.version from 4.17.0 to 4.17.1
  • #6851: chore(deps): bump io.github.apex-dev-tools:vf-parser from 2.0.0-beta.1 to 2.0.0
  • #6852: chore(deps-dev): bump log4j.version from 2.26.0 to 2.26.1
  • #6854: chore(deps): bump org.apache.groovy:groovy from 5.0.6 to 5.0.7
  • #6855: chore(deps-dev): bump byte.buddy.version from 1.18.10 to 1.18.11
  • #6857: chore(deps): bump org.checkerframework:checker-qual from 4.2.0 to 4.2.1
  • #6862: [apex] Fix #6478: Bump apex-parser from 5.0.0 to 5.1.0
  • #6872: chore: Bump maven from 3.9.14 to 3.9.16
  • #6873: chore(deps): bump net.sf.saxon:Saxon-HE from 12.9 to 12.10
  • #6874: chore(deps): bump ruby/setup-ruby from 1.316.0 to 1.318.0
  • #6875: chore(deps): bump scalameta.version from 4.17.1 to 4.17.2
  • #6876: chore(deps): bump junit.version from 6.1.1 to 6.1.2
  • #6878: chore(deps): bump com.puppycrawl.tools:checkstyle from 13.7.0 to 13.8.0
  • #6890: [apex][visualforce] Update apex-ls from 6.0.2 to 6.1.0
  • #6897: chore(deps): bump ruby/setup-ruby from 1.318.0 to 1.320.0
  • #6898: chore(deps): bump actions/checkout from 7.0.0 to 7.0.1
  • #6899: chore(deps): bump actions/setup-java from 5.5.0 to 5.6.0
  • #6907: chore(deps): bump ruby/setup-ruby from 1.320.0 to 1.321.0
  • #6908: chore(deps): bump scalameta.version from 4.17.2 to 4.17.3
  • #6909: chore(deps): bump csv from 3.3.5 to 3.3.6 in /docs
  • #6910: chore(deps): bump com.puppycrawl.tools:checkstyle from 13.8.0 to 13.10.0
  • #6911: chore(deps): bump org.apache.maven.plugins:maven-jar-plugin from 3.5.0 to 3.5.1
  • #6927: chore(deps): bump org.jsoup:jsoup from 1.22.2 to 1.23.1
  • #6928: chore(deps): bump org.cyclonedx:cyclonedx-maven-plugin from 2.9.2 to 2.9.3
  • #6929: chore(deps): bump actions/setup-java from 5.6.0 to 5.7.0
  • #6930: chore(deps): bump org.apache.groovy:groovy from 5.0.7 to 5.0.8
  • #6931: chore(deps): bump io.github.apex-dev-tools:apex-ls_2.13 from 6.1.0 to 6.2.0
  • #6969: chore(deps): bump junit.version from 6.1.2 to 6.1.3
  • #6970: chore(deps): bump crate-ci/typos from 1.48.0 to 1.49.0
  • #6971: chore(deps): bump org.checkerframework:checker-qual from 4.2.1 to 4.2.2
  • #6979: chore(deps): bump build-tools from 39 to 40
  • #6980: chore(deps): bump json from 2.19.2 to 2.19.9 in /docs
  • #6985: chore(deps-dev): bump com.google.guava:guava from 33.6.0-jre to 33.7.1-jre
  • #6986: chore(deps): bump org.apache.groovy:groovy from 5.0.8 to 5.1.0
  • #6997: chore(deps): bump com.google.protobuf:protobuf-java from 4.35.1 to 4.36.0
  • #6998: chore(deps-dev): bump byte.buddy.version from 1.18.11 to 1.18.12
  • #6999: chore(deps): bump com.puppycrawl.tools:checkstyle from 13.10.0 to 14.0.0
  • #7001: chore(deps): bump io.github.apex-dev-tools:apex-parser from 5.1.0 to 5.2.0

📈️ Stats

  • 120 commits
  • 124 closed tickets & PRs
  • Days since last release: 60

Don't miss a new pmd release

NewReleases is sending notifications on new releases.