PMD 7.18.0 released

31 October 2025


31-October-2025 - 7.18.0

The PMD team is pleased to announce PMD 7.18.0.

This is a minor release.

Table Of Contents

🚀️ New and noteworthy

Build Requirement is Java 17

From now on, Java 17 or newer is required to build PMD. PMD itself still remains compatible with Java 8, so that it still can be used in a pure Java 8 environment. This allows us to use the latest checkstyle version during the build.

🌟️ New and Changed Rules

New Rules

  • The new Java rule IdenticalConditionalBranches finds conditional statements that do the same thing when the condition is true and false. This is either incorrect or redundant.
  • The new Java rule LabeledStatement finds labeled statements in code. Labels make control flow difficult to understand and should be avoided. By default, the rule allows labeled loops (do, while, for). But it has a property to flag also those labeled loops.
  • The new Java rule UnusedLabel finds unused labels which are unnecessary and only make the code hard to read. This new rule will be part of the quickstart ruleset.

Changed Rules

  • ConfusingTernary has a new property nullCheckBranch to control, whether null-checks should be allowed (the default case) or should lead to a violation.
  • AvoidCatchingGenericException is now configurable with the new property typesThatShouldNotBeCaught.
    ⚠️ The rule has also been moved from category “Design” to category “Error Prone”. If you are currently bulk-adding all the rules from the “Design” category into your custom ruleset, then you need to add the rule explicitly again (otherwise it won’t be included anymore):
    <rule ref="category/java/errorprone.xml/AvoidCatchingGenericException" />
    

Deprecated Rules

🐛️ Fixed Issues

  • general
    • #4714: [core] Allow trailing commas in multivalued properties
    • #5873: [ci] Run integration test with Java 25
    • #6012: [pmd-rulesets] Rulesets should be in alphabetical order
    • #6073: [doc] Search improvements
    • #6097: [doc] Add PMD versions dropdown
    • #6098: [doc] Add a copy URL button
    • #6101: [doc] Highlight current header in TOC
    • #6149: [doc] Reproducible Build Documentation is outdated - PMD is now built using Java 17
    • #6150: [core] Reduce memory usage of CPD’s MatchCollector
  • apex
    • #5935: [apex] @SuppressWarnings - allow whitespace around comma when suppressing multiple rules
  • apex-design
    • #6022: [apex] ExcessiveClassLength/ExcessiveParameterList include the metric in the message
  • apex-documentation
    • #6189: [apex] ApexDoc rule doesn’t match published Salesforce ApexDoc specification
  • java
    • #4904: [java] Renderers output wrong class qualified name for nested classes
    • #6127: [java] Incorrect variable name in violation
    • #6132: [java] Implement main method launch protocol priorities
    • #6146: [java] ClassCastException: class InferenceVarSym cannot be cast to class JClassSymbol
  • java-bestpractices
    • #2928: [java] New rules about labeled statements
    • #4122: [java] CheckResultSet false-positive with local variable
    • #6124: [java] UnusedLocalVariable: fix false negatives in pattern matching
    • #6169: [java] AvoidUsingHardCodedIP: violation message should mention the hard coded address
    • #6171: [java] AvoidUsingHardCodedIP: fix false positive for IPv6
  • java-codestyle
    • #5919: [java] ClassNamingConventions: Include integration tests in testClassPattern by default
    • #6004: [java] Make ConfusingTernary != null configurable
    • #6029: [java] Fix UnnecessaryCast false-negative in method calls
    • #6057: [java] ModifierOrder false positive on “abstract sealed class”
    • #6079: [java] IdenticalCatchBranches: False negative for overriden method calls
    • #6123: [java] UselessParentheses FP around switch expression
    • #6131: [java] ModifierOrder: wrong enum values documented, indirectly causing xml parse errors
  • java-design
    • #1499: [java] AvoidDeeplyNestedIfStmts violations can be unintentionally undetected
    • #5569: [java] ExcessivePublicCount should report number of public “things”
  • java-documentation
    • #6058: [java] DanglingJavadoc FP in module-info files
    • #6103: [java] DanglingJavadoc false positive on record compact constructors
  • java-errorprone
    • #5042: [java] CloseResource false-positive on Pattern Matching with instanceof
    • #5878: [java] DontUseFloatTypeForLoopIndices false-negative if variable is declared before loop
    • #6038: [java] Merge AvoidCatchingNPE and AvoidCatchingThrowable into AvoidCatchingGenericException
    • #6055: [java] UselessPureMethodCall false positive with AtomicInteger::getAndIncrement
    • #6060: [java] UselessPureMethodCall false positive on ZipInputStream::getNextEntry
    • #6075: [java] AssignmentInOperand false positive with lambda expressions
    • #6083: [java] New rule IdenticalConditionalBranches
  • java-multithreading
    • #5880: [java] DoubleCheckedLocking is not detected if more than 1 assignment or more than 2 if statements
  • java-performance
    • #6172: [java] InefficientEmptyStringCheck should include String#strip
  • java-security
    • #6191: [java] HardCodedCryptoKey: NPE when constants from parent class are used
  • plsql-design
    • #6077: [plsql] Excessive*/Ncss*Count/NPathComplexity include the metric

🚨️ API Changes

Deprecations

✨️ Merged pull requests

  • #6021: [java] Fix #5569: ExcessiveImports/ExcessiveParameterList/ExcessivePublicCount include the metric in the message - UncleOwen (@UncleOwen)
  • #6022: [apex] ExcessiveClassLength/ExcessiveParameterList include the metric in the message - UncleOwen (@UncleOwen)
  • #6023: [test] Fix #6012: Alphabetically sort all default rules - Zbynek Konecny (@zbynek)
  • #6024: [java] Fix #5878: DontUseFloatTypeForLoopIndices now checks the UpdateStatement as well - UncleOwen (@UncleOwen)
  • #6029: [java] Fix UnnecessaryCast false-negative in method calls - Zbynek Konecny (@zbynek)
  • #6031: [java] Fix #5880: False Negatives in DoubleCheckedLocking - Lukas Gräf (@lukasgraef)
  • #6039: [core] Fix #4714: trim token before feeding it to the extractor - UncleOwen (@UncleOwen)
  • #6040: [java,apex,plsql,velocity] Change description of “minimum” parameter - UncleOwen (@UncleOwen)
  • #6042: [java] Fix #2928: New Rules UnusedLabel and LabeledStatement - UncleOwen (@UncleOwen)
  • #6043: [java] Reactivate deactivated test in LocalVariableCouldBeFinal - UncleOwen (@UncleOwen)
  • #6051: [java] Fix #6038: Make AvoidCatchingGenericException configurable - UncleOwen (@UncleOwen)
  • #6056: chore: fix dogfood issues from new rules - Andreas Dangel (@adangel)
  • #6059: [java] Fix #6058: DanglingJavadoc FP in module-info files - Lukas Gräf (@lukasgraef)
  • #6061: [core] chore: Bump minimum Java version required for building to 17 - Andreas Dangel (@adangel)
  • #6071: [java] Fix #5919: Add integration tests to ClassNamingConventions testClassRegex - Anton Bobov (@abobov)
  • #6073: [doc] Search improvements - Andreas Dangel (@adangel)
  • #6074: [apex] Fix @SuppressWarnings with whitespace around comma - Juan Martín Sotuyo Dodero (@jsotuyod)
  • #6077: [plsql] Excessive/NcssCount/NPathComplexity include the metric - Andreas Dangel (@adangel)
  • #6078: [java] Fix #6075: Fix FP in AssignmentInOperandRule - UncleOwen (@UncleOwen)
  • #6080: [java] Fix #6079: IdenticalCatchBranches for overriden method calls - Zbynek Konecny (@zbynek)
  • #6082: [java] Fix false positives in UselessPureMethodCall for streams and atomics - Zbynek Konecny (@zbynek)
  • #6083: [java] New rule IdenticalConditionalBranches - Zbynek Konecny (@zbynek)
  • #6085: [java] Fix false positive for ModifierOrder - Zbynek Konecny (@zbynek)
  • #6093: [ci] Fix #5873: Run integration tests with Java 25 additionally - Andreas Dangel (@adangel)
  • #6097: [doc] Add PMD versions dropdown - Andreas Dangel (@adangel)
  • #6098: [doc] Add a copy URL button - Andreas Dangel (@adangel)
  • #6100: [java] AvoidDeeplyNestedIfStmts: fix false negative with if-else - Zbynek Konecny (@zbynek)
  • #6101: [doc] Highlight current header in TOC - Andreas Dangel (@adangel)
  • #6112: [java] DanglingJavadoc: fix false positive for compact constructors - Zbynek Konecny (@zbynek)
  • #6114: [java] Fix #4122: CheckResultSet false-positive with local variable - Lukas Gräf (@lukasgraef)
  • #6116: [java] ConfusingTernary: add configuration property for null checks - Zbynek Konecny (@zbynek)
  • #6124: [java] UnusedLocalVariable: fix false negatives in pattern matching - Zbynek Konecny (@zbynek)
  • #6128: [java] Fix #4904: Correct class name in violation decorator - Andreas Dangel (@adangel)
  • #6129: [java] Fix #6127: Correct var name in violation decorator - Andreas Dangel (@adangel)
  • #6130: [java] UselessParentheses: fix false positives for switch expressions - Zbynek Konecny (@zbynek)
  • #6132: [java] Implement main method launch protocol priorities - Zbynek Konecny (@zbynek)
  • #6133: [java] Fix #5042: CloseResource: fix false positive with pattern matching - Zbynek Konecny (@zbynek)
  • #6150: [core] Reduce memory usage of CPD’s MatchCollector - Lukas Gräf (@lukasgraef)
  • #6152: chore(deps): Update Saxon-HE from 12.5 to 12.9 - Zbynek Konecny (@zbynek)
  • #6156: [java] Fix #6146: ClassCastException in TypeTestUtil - Clément Fournier (@oowekyala)
  • #6164: [doc] Update reproducible build info with Java 17 - Andreas Dangel (@adangel)
  • #6166: [doc] Use emoji variants - Andreas Dangel (@adangel)
  • #6170: [java] Fix #6169: AvoidUsingHardCodedIP - mention address in message - Andreas Dangel (@adangel)
  • #6171: [java] AvoidUsingHardCodedIP: fix false positive for IPv6 - Andreas Dangel (@adangel)
  • #6172: [java] InefficientEmptyStringCheck should include String#strip - Zbynek Konecny (@zbynek)
  • #6185: [java] Fix #6131: Correct enum values for ModifierOrder - Andreas Dangel (@adangel)
  • #6190: [apex] Update ApexDoc rule to match the published specification - Mitch Spano (@mitchspano)
  • #6191: [java] HardCodedCryptoKey: NPE when constants from parent class are used - Zbynek Konecny (@zbynek)

📦️ Dependency updates

  • #6034: chore(deps): bump com.puppycrawl.tools:checkstyle from 10.26.1 to 11.0.1
  • #6054: Bump PMD from 7.16.0 to 7.17.0
  • #6062: chore(deps): bump surefire.version from 3.5.3 to 3.5.4
  • #6063: chore(deps): bump ruby/setup-ruby from 1.257.0 to 1.258.0
  • #6064: chore(deps): bump com.google.code.gson:gson from 2.13.1 to 2.13.2
  • #6065: chore(deps): bump actions/create-github-app-token from 2.1.1 to 2.1.4
  • #6066: chore(deps): bump org.apache.groovy:groovy from 5.0.0 to 5.0.1
  • #6067: chore(deps): bump org.apache.maven.plugins:maven-shade-plugin from 3.6.0 to 3.6.1
  • #6068: chore(deps): bump scalameta.version from 4.13.9 to 4.13.10
  • #6076: Bump pmdtester from 1.6.0 to 1.6.1
  • #6086: chore(deps): bump ruby/setup-ruby from 1.258.0 to 1.263.0
  • #6087: chore(deps-dev): bump log4j.version from 2.25.1 to 2.25.2
  • #6088: chore(deps): bump org.mockito:mockito-core from 5.19.0 to 5.20.0
  • #6089: chore(deps): bump org.apache.maven.plugins:maven-javadoc-plugin from 3.11.3 to 3.12.0
  • #6090: chore(deps): bump org.codehaus.mojo:versions-maven-plugin from 2.19.0 to 2.19.1
  • #6091: chore(deps): bump org.apache.maven.plugins:maven-compiler-plugin from 3.14.0 to 3.14.1
  • #6094: chore(deps): Bump rexml from 3.4.1 to 3.4.4
  • #6104: chore(deps): bump actions/cache from 4.2.4 to 4.3.0
  • #6105: chore(deps): bump org.scala-lang:scala-library from 2.13.16 to 2.13.17
  • #6106: chore(deps): bump junit.version from 5.13.4 to 6.0.0
  • #6107: chore(deps): bump org.codehaus.mojo:exec-maven-plugin from 3.5.1 to 3.6.0
  • #6108: chore(deps): bump com.puppycrawl.tools:checkstyle from 10.26.1 to 11.1.0
  • #6109: chore(deps-dev): bump org.assertj:assertj-core from 3.27.4 to 3.27.6
  • #6110: chore(deps): bump org.sonatype.central:central-publishing-maven-plugin from 0.8.0 to 0.9.0
  • #6118: chore(deps): bump com.google.protobuf:protobuf-java from 4.32.0 to 4.32.1
  • #6119: chore(deps): bump com.github.hazendaz.maven:coveralls-maven-plugin from 4.7.0 to 5.0.0
  • #6120: chore(deps): bump org.scala-lang:scala-reflect from 2.13.16 to 2.13.17
  • #6121: chore(deps): bump com.github.siom79.japicmp:japicmp-maven-plugin from 0.23.1 to 0.24.1
  • #6122: chore(deps): bump bigdecimal from 3.2.3 to 3.3.0 in /docs
  • #6136: chore(deps): bump ruby/setup-ruby from 1.263.0 to 1.265.0
  • #6137: chore(deps): bump org.apache.maven.plugins:maven-enforcer-plugin from 3.6.1 to 3.6.2
  • #6138: chore(deps): bump scalameta.version from 4.13.10 to 4.14.0
  • #6139: chore(deps): bump com.puppycrawl.tools:checkstyle from 11.1.0 to 12.0.1
  • #6140: chore(deps): bump org.codehaus.mojo:exec-maven-plugin from 3.6.0 to 3.6.1
  • #6141: chore(deps): bump org.ow2.asm:asm from 9.8 to 9.9
  • #6142: chore(deps): bump org.apache.commons:commons-lang3 from 3.18.0 to 3.19.0
  • #6143: chore(deps): bump bigdecimal from 3.3.0 to 3.3.1 in /docs
  • #6152: chore(deps): Update Saxon-HE from 12.5 to 12.9
  • #6157: chore(deps-dev): bump com.google.guava:guava from 33.4.8-jre to 33.5.0-jre
  • #6158: chore(deps): bump scalameta.version from 4.14.0 to 4.14.1
  • #6159: chore(deps): bump org.apache.maven.plugins:maven-dependency-plugin from 3.8.1 to 3.9.0
  • #6160: chore(deps): bump com.github.siom79.japicmp:japicmp-maven-plugin from 0.24.1 to 0.24.2
  • #6161: chore(deps): bump org.apache.maven.plugins:maven-pmd-plugin from 3.27.0 to 3.28.0
  • #6162: chore(deps): bump org.apache.maven.plugins:maven-antrun-plugin from 3.1.0 to 3.2.0
  • #6165: Bump pmdtester from 1.6.1 to 1.6.2
  • #6173: chore(deps): bump actions/upload-artifact from 4.6.2 to 5.0.0
  • #6174: chore(deps): bump ruby/setup-ruby from 1.265.0 to 1.267.0
  • #6175: chore(deps): bump actions/download-artifact from 5.0.0 to 6.0.0
  • #6178: chore(deps): bump org.checkerframework:checker-qual from 3.49.5 to 3.51.1
  • #6179: chore(deps): bump org.codehaus.mojo:exec-maven-plugin from 3.6.1 to 3.6.2
  • #6180: chore(deps): bump io.github.apex-dev-tools:apex-ls_2.13 from 5.10.0 to 6.0.1
  • #6181: chore(deps): bump org.apache.groovy:groovy from 5.0.1 to 5.0.2
  • #6182: chore(deps-dev): bump net.bytebuddy:byte-buddy from 1.17.7 to 1.17.8

📈️ Stats

  • 233 commits
  • 76 closed tickets & PRs
  • Days since last release: 49