Skip to content

Commit 5be481e

Browse files
committed
[java] Support Java 24 (#5471)
Merge pull request #5471 from adangel:issue-5154-java-24
2 parents d8886e3 + 06d6810 commit 5be481e

47 files changed

Lines changed: 1783 additions & 1910 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/pages/pmd/languages/java.md

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
title: Java support
33
permalink: pmd_languages_java.html
44
author: Clément Fournier
5-
last_updated: July 2024 (7.5.0)
5+
last_updated: January 2025 (7.10.0)
66
tags: [languages, PmdCapableLanguage, CpdCapableLanguage]
77
summary: "Java-specific features and guidance"
88
---
@@ -15,9 +15,10 @@ Usually the latest non-preview Java Version is the default version.
1515

1616
| Java Version | Alias | Supported by PMD since |
1717
|--------------|-------|------------------------|
18+
| 24-preview | | 7.10.0 |
19+
| 24 (default) | | 7.10.0 |
1820
| 23-preview | | 7.5.0 |
19-
| 23 (default) | | 7.5.0 |
20-
| 22-preview | | 7.0.0 |
21+
| 23 | | 7.5.0 |
2122
| 22 | | 7.0.0 |
2223
| 21 | | 7.0.0 |
2324
| 20 | | 6.55.0 |
@@ -42,10 +43,10 @@ Usually the latest non-preview Java Version is the default version.
4243
## Using Java preview features
4344

4445
In order to analyze a project with PMD that uses preview language features, you'll need to enable
45-
it via the environment variable `PMD_JAVA_OPTS` and select the new language version, e.g. `22-preview`:
46+
it via the environment variable `PMD_JAVA_OPTS` and select the new language version, e.g. `24-preview`:
4647

4748
export PMD_JAVA_OPTS=--enable-preview
48-
pmd check --use-version java-22-preview ...
49+
pmd check --use-version java-24-preview ...
4950

5051
Note: we only support preview language features for the latest two java versions.
5152

docs/pages/pmd/userdocs/tools/ant.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ author: >
66
David Dixon-Peugh <dpeugh@users.sourceforge.net>,
77
Tom Copeland <tom@infoether.com>,
88
Xavier Le Vourch <xlv@users.sourceforge.net>
9-
last_updated: June 2024 (7.3.0)
9+
last_updated: January 2025 (7.10.0)
1010
---
1111

1212
## PMD
@@ -213,7 +213,7 @@ accordingly and this rule won't be executed.
213213
The specific version of a language to be used is selected via the `sourceLanguage`
214214
nested element. Example:
215215

216-
<sourceLanguage name="java" version="23"/>
216+
<sourceLanguage name="java" version="24"/>
217217

218218
The available versions depend on the language. You can get a list of the currently supported language versions
219219
via the CLI option `--help`.

docs/pages/release_notes.md

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,25 @@ This is a {{ site.pmd.release_type }} release.
1414

1515
### 🚀 New and noteworthy
1616

17+
#### 🚀 New: Java 24 Support
18+
This release of PMD brings support for Java 24. There are no new standard language features,
19+
but a couple of preview language features:
20+
21+
* [JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview)](https://openjdk.org/jeps/488)
22+
* [JEP 492: Flexible Constructor Bodies (Third Preview)](https://openjdk.org/jeps/492)
23+
* [JEP 494: Module Import Declarations (Second Preview)](https://openjdk.org/jeps/494)
24+
* [JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)](https://openjdk.org/jeps/495)
25+
26+
In order to analyze a project with PMD that uses these preview language features,
27+
you'll need to enable it via the environment variable `PMD_JAVA_OPTS` and select the new language
28+
version `24-preview`:
29+
30+
export PMD_JAVA_OPTS=--enable-preview
31+
pmd check --use-version java-24-preview ...
32+
33+
Note: Support for Java 22 preview language features have been removed. The version "22-preview"
34+
are no longer available.
35+
1736
#### New GPG Release Signing Key
1837

1938
Since January 2025, we switched the GPG Key we use for signing releases in Maven Central to be
@@ -52,14 +71,24 @@ For the changes, see [PMD Designer Changelog (7.10.0)](https://github.com/pmd/pm
5271
* [#3158](https://github.com/pmd/pmd/issues/3158): \[apex] ApexSuggestUsingNamedCred false positive with Named Credential merge fields
5372
* documentation
5473
* [#2492](https://github.com/pmd/pmd/issues/2492): \[doc] Promote wiki pages to standard doc pages
74+
* java
75+
* [#5154](https://github.com/pmd/pmd/issues/5154): \[java] Support Java 24
5576
* java-performance
5677
* [#5311](https://github.com/pmd/pmd/issues/5311): \[java] TooFewBranchesForSwitch false positive for exhaustive switches over enums without default case
5778

5879
### 🚨 API Changes
5980

81+
#### Removed Experimental API
82+
* pmd-java
83+
* `net.sourceforge.pmd.lang.java.ast.ASTTemplate`, `net.sourceforge.pmd.lang.java.ast.ASTTemplateExpression`,
84+
`net.sourceforge.pmd.lang.java.ast.ASTTemplateFragment`: These nodes were introduced with Java 21 and 22
85+
Preview to support String Templates. However, the String Template preview feature was not finalized
86+
and has been removed from Java for now. We now cleaned up the PMD implementation of it.
87+
6088
### ✨ Merged pull requests
6189
<!-- content will be automatically generated, see /do-release.sh -->
6290
* [#5412](https://github.com/pmd/pmd/pull/5412): \[java] Support exhaustive switches - [Andreas Dangel](https://github.com/adangel) (@adangel)
91+
* [#5471](https://github.com/pmd/pmd/pull/5471): \[java] Support Java 24 - [Andreas Dangel](https://github.com/adangel) (@adangel)
6392
* [#5488](https://github.com/pmd/pmd/pull/5488): \[apex] Fix #3158: Recognize Named Credentials merge fields in ApexSuggestUsingNamedCredRule - [William Brockhus](https://github.com/YodaDaCoda) (@YodaDaCoda)
6493

6594
### 📦 Dependency updates

pmd-cli/src/main/java/net/sourceforge/pmd/cli/PmdCli.java

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,20 @@ public final class PmdCli {
1212

1313
private PmdCli() { }
1414

15-
public static void main(String[] args) {
15+
// package private for test only without calling System.exit
16+
static int mainWithoutExit(String[] args) {
1617
// See https://github.com/remkop/picocli/blob/main/RELEASE-NOTES.md#-picocli-470
1718
// and https://picocli.info/#_closures_in_annotations
1819
// we don't use this feature. Disabling it avoids leaving the groovy jar open
1920
// caused by Class.forName("groovy.lang.Closure")
2021
System.setProperty("picocli.disable.closures", "true");
2122
final CommandLine cli = new CommandLine(new PmdRootCommand())
2223
.setCaseInsensitiveEnumValuesAllowed(true);
23-
24-
System.exit(cli.execute(args));
24+
25+
return cli.execute(args);
26+
}
27+
28+
public static void main(String[] args) {
29+
System.exit(mainWithoutExit(args));
2530
}
2631
}

pmd-cli/src/test/java/net/sourceforge/pmd/cli/BaseCliTest.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.ArrayList;
1414
import java.util.Arrays;
1515
import java.util.List;
16+
import java.util.concurrent.atomic.AtomicReference;
1617
import java.util.regex.Pattern;
1718

1819
import org.apache.commons.lang3.StringUtils;
@@ -55,26 +56,25 @@ protected CliExecutionResult runCli(CliExitCode expectedExitCode, String... args
5556
final PrintStream formerOut = System.out;
5657
final PrintStream formerErr = System.err;
5758

58-
CliExitCode exitCode;
59+
final AtomicReference<CliExitCode> exitCode = new AtomicReference<>();
5960
try {
6061
System.out.println("running: pmd " + String.join(" ", argList));
6162
System.setOut(new PrintStream(out));
6263
System.setErr(new PrintStream(err));
63-
int actualExitCode = SystemLambda.catchSystemExit(
64-
// restoring system properties: --debug might change logging properties
65-
() -> SystemLambda.restoreSystemProperties(
66-
() -> PmdCli.main(argList.toArray(new String[0]))
67-
)
64+
// restoring system properties: --debug might change logging properties
65+
SystemLambda.restoreSystemProperties(
66+
() -> {
67+
int actualExitCode = PmdCli.mainWithoutExit(argList.toArray(new String[0]));
68+
exitCode.set(CliExitCode.fromInt(actualExitCode));
69+
}
6870
);
69-
exitCode = CliExitCode.fromInt(actualExitCode);
70-
7171
} finally {
7272
System.setOut(formerOut);
7373
System.setErr(formerErr);
7474
}
7575

7676
return new CliExecutionResult(
77-
out, err, exitCode
77+
out, err, exitCode.get()
7878
).verify(e -> assertEquals(expectedExitCode, e.exitCode));
7979
}
8080

pmd-dist/src/test/java/net/sourceforge/pmd/dist/BinaryDistributionIT.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,9 @@ class BinaryDistributionIT extends AbstractBinaryDistributionTest {
5252
"java-16", "java-17", "java-18", "java-19",
5353
"java-20",
5454
"java-21",
55-
"java-22", "java-22-preview",
55+
"java-22",
5656
"java-23", "java-23-preview",
57+
"java-24", "java-24-preview",
5758
"java-5", "java-6", "java-7",
5859
"java-8", "java-9", "jsp-2", "jsp-3", "kotlin-1.6",
5960
"kotlin-1.7", "kotlin-1.8", "modelica-3.4", "modelica-3.5",

pmd-java/etc/grammar/Java.jjt

Lines changed: 5 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
/**
2+
* Removed support for String Templates, introduced in Java 21 / 22 Preview
3+
* Andreas Dangel 01/2025
4+
*====================================================================
25
* Support "JEP 455: Primitive Types in Patterns, instanceof, and switch (Preview)" (Java 23)
36
* Changes in InstanceOfExpression
47
* Support "JEP 476: Module Import Declarations (Preview)" (Java 23)
@@ -614,50 +617,6 @@ PARSER_END(JavaParserImpl)
614617
TOKEN_MGR_DECLS :
615618
{
616619
protected List<JavaComment> comments = new ArrayList<JavaComment>();
617-
private Deque<Boolean> savedTemplateKind = new ArrayDeque<Boolean>();
618-
private Deque<Integer> braceDepthInTemplate = new ArrayDeque<Integer>();
619-
private int braceDepthCurrentTemplate;
620-
private boolean templateKind;
621-
622-
private static final java.util.regex.Pattern TEXT_BLOCK_TEMPLATE_END_PATTERN =
623-
java.util.regex.Pattern.compile("^}[^\"]*\"\"\"");
624-
private static final java.util.regex.Pattern STRING_TEMPLATE_MID_OR_END_PATTERN =
625-
java.util.regex.Pattern.compile("^}(?:[^\"\\\\\n\r]|\\\\(?:[ntbrfs\\\\'\"]|[0-7][0-7]?|[0-3][0-7][0-7]))*(\\{|\")");
626-
627-
private void pushBrace() {
628-
braceDepthCurrentTemplate++;
629-
}
630-
private void pushTemplate(boolean isTextBlockTemplate) {
631-
braceDepthInTemplate.push(braceDepthCurrentTemplate);
632-
savedTemplateKind.push(templateKind);
633-
templateKind = isTextBlockTemplate;
634-
braceDepthCurrentTemplate = 1;
635-
}
636-
private boolean isInTemplate() {
637-
return braceDepthCurrentTemplate > 0;
638-
}
639-
private void popBrace() {
640-
if (!isInTemplate())
641-
return;
642-
if (--braceDepthCurrentTemplate == 0) {
643-
// this brace ends the template
644-
popTemplate();
645-
}
646-
}
647-
private void popTemplate() {
648-
boolean isInTextBlockTemplate = templateKind;
649-
if (!braceDepthInTemplate.isEmpty()) {
650-
braceDepthCurrentTemplate = braceDepthInTemplate.pop();
651-
templateKind = savedTemplateKind.pop();
652-
if (isInTextBlockTemplate) {
653-
SwitchTo(JavaTokenKinds.IN_TEXT_BLOCK_LITERAL);
654-
} else {
655-
SwitchTo(JavaTokenKinds.IN_STRING_TEMPLATE);
656-
}
657-
} else {
658-
SwitchTo(JavaTokenKinds.DEFAULT);
659-
}
660-
}
661620
private net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken rereadTokenAs(int kind, int length) {
662621
input_stream.backup(lengthOfMatch);
663622
try {
@@ -670,14 +629,6 @@ TOKEN_MGR_DECLS :
670629
jjmatchedKind = kind;
671630
return jjFillToken();
672631
}
673-
674-
private net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken handleBlock() {
675-
net.sourceforge.pmd.lang.ast.impl.javacc.JavaccToken matchedToken = rereadTokenAs(JavaTokenKinds.RBRACE, 1);
676-
if (!"}".equals(input_stream.getTokenImage())) {
677-
throw new IllegalStateException("Expected '}'");
678-
}
679-
return matchedToken;
680-
}
681632
}
682633

683634
/* WHITE SPACE */
@@ -859,8 +810,6 @@ TOKEN :
859810
)
860811
>
861812
| < #TEXT_BLOCK_CHARACTER: ~["\\"] | <STRING_ESCAPE> | ("\\")? <LINE_TERMINATOR> >
862-
| < #STRING_FRAGMENT: (<STRING_CHARACTER>)* >
863-
| < STRING_TEMPLATE_BEGIN: "\"" <STRING_FRAGMENT> "\\{" > { pushTemplate(false); }
864813
}
865814

866815
/* TEXT BLOCKS */
@@ -874,7 +823,6 @@ MORE :
874823
<IN_TEXT_BLOCK_LITERAL>
875824
TOKEN : {
876825
<TEXT_BLOCK_LITERAL: "\"\"\"" > : DEFAULT
877-
| <TEXT_BLOCK_TEMPLATE_MID: "\\{"> { pushTemplate(true); }: DEFAULT
878826
}
879827

880828
<IN_TEXT_BLOCK_LITERAL>
@@ -883,13 +831,6 @@ MORE :
883831
< <TEXT_BLOCK_CHARACTER> >
884832
}
885833

886-
<IN_STRING_TEMPLATE>
887-
TOKEN:
888-
{
889-
< STRING_TEMPLATE_END: <STRING_FRAGMENT> "\"" > : DEFAULT
890-
| < STRING_TEMPLATE_MID: <STRING_FRAGMENT> "\\{" > { pushTemplate(false); } : DEFAULT
891-
}
892-
893834
/* IDENTIFIERS */
894835

895836
TOKEN :
@@ -1027,8 +968,8 @@ TOKEN :
1027968
{
1028969
< LPAREN: "(" >
1029970
| < RPAREN: ")" >
1030-
| < LBRACE: "{" > { pushBrace(); }
1031-
| < RBRACE: "}" > { popBrace(); }
971+
| < LBRACE: "{" >
972+
| < RBRACE: "}" >
1032973
| < LBRACKET: "[" >
1033974
| < RBRACKET: "]" >
1034975
| < SEMICOLON: ";" >
@@ -2186,7 +2127,6 @@ void PrimaryStep2() #void:
21862127
// "super" alone is not a valid expression
21872128
("." MemberSelector() | MethodReference())
21882129
| MemberSelector()
2189-
| {forceExprContext();} Template() #TemplateExpression(2)
21902130
)
21912131
// catches the case where the ambig name is the start of an array type
21922132
| LOOKAHEAD("@" | "[" "]") {forceTypeContext();} Dims() #ArrayType(2) (MethodReference() | "." "class" #ClassLiteral(1))
@@ -2291,41 +2231,6 @@ boolean LambdaParameterType() #void :
22912231
| FormalParamType() { return false; }
22922232
}
22932233

2294-
void Template() :
2295-
{}
2296-
{
2297-
StringTemplate()
2298-
| TextBlockTemplate()
2299-
| <STRING_LITERAL> #TemplateFragment
2300-
| <TEXT_BLOCK_LITERAL> #TemplateFragment
2301-
2302-
}
2303-
2304-
void StringTemplate() #void :
2305-
{}
2306-
{
2307-
<STRING_TEMPLATE_BEGIN> #TemplateFragment
2308-
EmbeddedExpression()
2309-
(LOOKAHEAD(2) (<RBRACE> <STRING_TEMPLATE_MID> ) #TemplateFragment EmbeddedExpression() )*
2310-
(<RBRACE> <STRING_TEMPLATE_END>) #TemplateFragment
2311-
}
2312-
2313-
void TextBlockTemplate() #void :
2314-
{}
2315-
{
2316-
2317-
<TEXT_BLOCK_TEMPLATE_MID> #TemplateFragment
2318-
EmbeddedExpression()
2319-
(LOOKAHEAD(2) ( <RBRACE> <TEXT_BLOCK_TEMPLATE_MID> ) #TemplateFragment EmbeddedExpression() )*
2320-
(<RBRACE> <TEXT_BLOCK_LITERAL>) #TemplateFragment
2321-
}
2322-
2323-
void EmbeddedExpression() #void :
2324-
{}
2325-
{
2326-
[ Expression() ]
2327-
}
2328-
23292234
void Literal() #void :
23302235
{}
23312236
{

pmd-java/pom.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@
138138
<exclude>net.sourceforge.pmd.lang.java.symbols.table.internal</exclude>
139139
<exclude>net.sourceforge.pmd.lang.java.types.internal</exclude>
140140
<exclude>net.sourceforge.pmd.lang.java.types.ast.internal</exclude>
141+
<!-- Template, TemplateExpression, TemplateFragment have been Experimental and
142+
now removed with 7.10.0. These were part of String Templates, introduced with Java 21/22 Preview
143+
but removed with Java 23.
144+
-->
145+
<exclude>net.sourceforge.pmd.lang.java.ast.JavaVisitor#visit(net.sourceforge.pmd.lang.java.ast.ASTTemplate,java.lang.Object)</exclude>
146+
<exclude>net.sourceforge.pmd.lang.java.ast.JavaVisitor#visit(net.sourceforge.pmd.lang.java.ast.ASTTemplateExpression,java.lang.Object)</exclude>
147+
<exclude>net.sourceforge.pmd.lang.java.ast.JavaVisitor#visit(net.sourceforge.pmd.lang.java.ast.ASTTemplateFragment,java.lang.Object)</exclude>
141148
</excludes>
142149
</parameter>
143150
</configuration>

pmd-java/src/main/java/net/sourceforge/pmd/lang/java/JavaLanguageModule.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,9 +44,10 @@ public JavaLanguageModule() {
4444
.addVersion("20")
4545
.addVersion("21")
4646
.addVersion("22")
47-
.addVersion("22-preview")
48-
.addDefaultVersion("23") // 23 is the default
49-
.addVersion("23-preview"));
47+
.addVersion("23")
48+
.addVersion("23-preview")
49+
.addDefaultVersion("24") // 24 is the default
50+
.addVersion("24-preview"));
5051
}
5152

5253
public static JavaLanguageModule getInstance() {

pmd-java/src/main/java/net/sourceforge/pmd/lang/java/ast/ASTImplicitClassDeclaration.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@
1919
* </pre>
2020
*
2121
* @see <a href="https://openjdk.org/jeps/477">JEP 477: Implicitly Declared Classes and Instance Main Methods (Third Preview)</a> (Java 23)
22+
* @see <a href="https://openjdk.org/jeps/495">JEP 495: Simple Source Files and Instance Main Methods (Fourth Preview)</a> (Java 24)
2223
*/
23-
@Experimental("Implicitly Declared Classes and Instance Main Methods is a Java 22 / Java 23 Preview feature")
24+
@Experimental("Simple Source Files and Instance Main Methods is a Java 22 / Java 23 / Java 24 Preview feature")
2425
public final class ASTImplicitClassDeclaration extends AbstractTypeDeclaration {
2526
ASTImplicitClassDeclaration(int id) {
2627
super(id);

0 commit comments

Comments
 (0)