Skip to content

Commit caeaf59

Browse files
committed
Merge pull request #1 from adangel:add-java21-samples
Add java21 samples from PMD #1
2 parents 4054396 + c984541 commit caeaf59

16 files changed

+844
-2
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ jobs:
88
- uses: actions/setup-java@v3
99
with:
1010
distribution: 'temurin'
11-
java-version: '19'
11+
java-version: '21'
1212
cache: 'maven'
1313
- name: Build with Maven
1414
run: ./mvnw --show-version --no-transfer-progress --errors --batch-mode package
49.6 KB
Binary file not shown.

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<packaging>jar</packaging>
88

99
<properties>
10-
<maven.compiler.release>19</maven.compiler.release>
10+
<maven.compiler.release>21</maven.compiler.release>
1111
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
1212
<!-- fixing the build timestamp of the jar so that the jar file only changes, if content changes.
1313
the actual timestamp is irrelevant. -->
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
package net.sourceforge.pmd.java.regression.tests.java21;
3+
4+
/*
5+
* Tests parsing after supporting String Templates. "}" is ambiguous.
6+
*/
7+
8+
@MyAnnotation(a = { "a" }, b = "b") // "}" might be recognized as STRING_TEMPLATE_END, but it is not
9+
class AnnotationValueInitializers { }
10+
11+
@MyAnnotation(a = { "a" }, b = "#b") // "}" might be recognized as STRING_TEMPLATE_END, but it is not
12+
class AnnotationValueInitializers2 { }
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
package net.sourceforge.pmd.java.regression.tests.java21;
3+
4+
/**
5+
* @see <a href="https://openjdk.org/jeps/441">JEP 441: Pattern Matching for switch</a>
6+
*/
7+
public class DealingWithNull {
8+
9+
static void testFooBar(String s) {
10+
switch (s) {
11+
case null -> System.out.println("Oops");
12+
case "Foo", "Bar" -> System.out.println("Great"); // CaseConstant
13+
default -> System.out.println("Ok");
14+
}
15+
}
16+
17+
static void testStringOrNull(Object o) {
18+
switch (o) {
19+
case String s -> System.out.println("String: " + s); // CasePattern
20+
case null -> System.out.println("null");
21+
default -> System.out.println("default case");
22+
}
23+
}
24+
25+
static void testStringOrDefaultNull(Object o) {
26+
switch (o) {
27+
case String s -> System.out.println("String: " + s);
28+
case null, default -> System.out.println("null or default case");
29+
}
30+
}
31+
32+
static void test2(Object o) {
33+
switch (o) {
34+
case null -> throw new NullPointerException();
35+
case String s -> System.out.println("String: "+s);
36+
case Integer i -> System.out.println("Integer");
37+
default -> System.out.println("default");
38+
}
39+
}
40+
41+
42+
static void test3(Object o) {
43+
switch(o) {
44+
case null:
45+
System.out.println("null");
46+
break; // note: fall-through to a CasePattern is not allowed, as the pattern variable is not initialized
47+
case String s:
48+
System.out.println("String");
49+
break;
50+
default:
51+
System.out.println("default case");
52+
break;
53+
}
54+
55+
switch(o) {
56+
case null -> System.out.println("null");
57+
case String s -> System.out.println("String");
58+
default -> System.out.println("default case");
59+
}
60+
61+
switch(o) {
62+
case null: default:
63+
System.out.println("The rest (including null)");
64+
}
65+
66+
switch(o) {
67+
case null, default ->
68+
System.out.println("The rest (including null)");
69+
}
70+
}
71+
72+
public static void main(String[] args) {
73+
testStringOrDefaultNull("test");
74+
test2(2);
75+
try {
76+
test2(null);
77+
} catch (NullPointerException e) {
78+
System.out.println(e);
79+
}
80+
test3(3);
81+
test3("test");
82+
test3(null);
83+
84+
testFooBar(null);
85+
testFooBar("Foo");
86+
testFooBar("Bar");
87+
testFooBar("baz");
88+
89+
testStringOrNull(null);
90+
testStringOrNull("some string");
91+
}
92+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
package net.sourceforge.pmd.java.regression.tests.java21;
3+
4+
/**
5+
* @see <a href="https://openjdk.org/jeps/441">JEP 441: Pattern Matching for switch</a>
6+
*/
7+
public class EnhancedTypeCheckingSwitch {
8+
9+
// As of Java 21
10+
// Selector expression typing
11+
record Point(int i, int j) {}
12+
enum Color { RED, GREEN, BLUE; }
13+
14+
static void typeTester(Object obj) {
15+
switch (obj) {
16+
case null -> System.out.println("null");
17+
case String s -> System.out.println("String");
18+
case Color c -> System.out.println("Color: " + c.toString());
19+
case Point p -> System.out.println("Record class: " + p.toString());
20+
case int[] ia -> System.out.println("Array of ints of length" + ia.length);
21+
default -> System.out.println("Something else");
22+
}
23+
}
24+
25+
public static void main(String[] args) {
26+
Object o = "test";
27+
typeTester(o);
28+
typeTester(Color.BLUE);
29+
30+
o = new int[] {1, 2, 3, 4};
31+
typeTester(o);
32+
33+
o = new Point(7, 8);
34+
typeTester(o);
35+
36+
o = new Object();
37+
typeTester(o);
38+
}
39+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
package net.sourceforge.pmd.java.regression.tests.java21;
3+
4+
/**
5+
* @see <a href="https://openjdk.org/jeps/441">JEP 441: Pattern Matching for switch</a>
6+
*/
7+
public class ExhaustiveSwitch {
8+
9+
// As of Java 21
10+
// Type coverage
11+
static int coverage(Object obj) {
12+
return switch (obj) {
13+
case String s -> s.length();
14+
case Integer i -> i;
15+
default -> 0;
16+
};
17+
}
18+
19+
static void coverageStatement(Object o) {
20+
switch (o) {
21+
case String s:
22+
System.out.println(s);
23+
break;
24+
case Integer i:
25+
System.out.println("Integer");
26+
break;
27+
default: // Now exhaustive!
28+
break;
29+
}
30+
}
31+
32+
// As of Java 21
33+
// Exhaustiveness and sealed classes
34+
sealed interface S permits A, B, C {}
35+
final static class A implements S {}
36+
final static class B implements S {}
37+
record C(int i) implements S {} // Implicitly final
38+
39+
static int testSealedExhaustive(S s) {
40+
return switch (s) {
41+
case A a -> 1;
42+
case B b -> 2;
43+
case C c -> 3;
44+
};
45+
}
46+
47+
static void switchStatementExhaustive(S s) {
48+
switch (s) {
49+
case A a :
50+
System.out.println("A");
51+
break;
52+
case C c :
53+
System.out.println("C");
54+
break;
55+
default:
56+
System.out.println("default case, should be B");
57+
break;
58+
};
59+
}
60+
61+
// As of Java 21
62+
// Exhaustiveness and sealed classes
63+
sealed interface I<T> permits E, F {}
64+
final static class E<X> implements I<String> {}
65+
final static class F<Y> implements I<Y> {}
66+
67+
static int testGenericSealedExhaustive(I<Integer> i) {
68+
return switch (i) {
69+
// Exhaustive as no E case possible!
70+
case F<Integer> bi -> 42;
71+
};
72+
}
73+
74+
public static void main(String[] args) {
75+
System.out.println(coverage("a string"));
76+
System.out.println(coverage(42));
77+
System.out.println(coverage(new Object()));
78+
79+
coverageStatement("a string");
80+
coverageStatement(21);
81+
coverageStatement(new Object());
82+
83+
System.out.println("A:" + testSealedExhaustive(new A()));
84+
System.out.println("B:" + testSealedExhaustive(new B()));
85+
System.out.println("C:" + testSealedExhaustive(new C(1)));
86+
87+
switchStatementExhaustive(new A());
88+
switchStatementExhaustive(new B());
89+
switchStatementExhaustive(new C(2));
90+
91+
System.out.println("F:" + testGenericSealedExhaustive(new F<Integer>()));
92+
}
93+
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
package net.sourceforge.pmd.java.regression.tests.java21;
3+
4+
/**
5+
* @see <a href="https://openjdk.org/jeps/441">JEP 441: Pattern Matching for switch</a>
6+
*/
7+
public class GuardedPatterns {
8+
9+
10+
static void test(Object o) {
11+
switch (o) {
12+
case String s when s.length() == 1 -> System.out.println("single char string");
13+
case String s -> System.out.println("string");
14+
case Integer i when i.intValue() == 1 -> System.out.println("integer 1");
15+
default -> System.out.println("default case");
16+
}
17+
}
18+
19+
// verify that "when" can still be used as an identifier -> formal parameter
20+
void testIdentifierWhen(String when) {
21+
System.out.println(when);
22+
}
23+
24+
// verify that "when" can still be used as an identifier -> local variable
25+
void testIdentifierWhen() {
26+
int when = 1;
27+
System.out.println(when);
28+
}
29+
30+
// verify that "when" can still be used as a type name
31+
private static class when {}
32+
33+
static void testWithNull(Object o) {
34+
switch (o) {
35+
case String s when (s.length() == 1) -> System.out.println("single char string");
36+
case String s -> System.out.println("string");
37+
case Integer i when i.intValue() == 1 -> System.out.println("integer 1");
38+
case null -> System.out.println("null!");
39+
default -> System.out.println("default case");
40+
}
41+
}
42+
43+
44+
static void instanceOfPattern(Object o) {
45+
if (o instanceof String s && s.length() > 2) {
46+
System.out.println("A string containing at least two characters");
47+
}
48+
if (o != null && (o instanceof String s && s.length() > 3)) {
49+
System.out.println("A string containing at least three characters");
50+
}
51+
52+
// note: with this 3rd preview, the following is not allowed anymore:
53+
// if (o instanceof (String s && s.length() > 4)) {
54+
// > An alternative to guarded pattern labels is to support guarded patterns directly as a special pattern form,
55+
// > e.g. p && e. Having experimented with this in previous previews, the resulting ambiguity with boolean
56+
// > expressions have lead us to prefer when clauses in pattern switches.
57+
if ((o instanceof String s) && (s.length() > 4)) {
58+
System.out.println("A string containing at least four characters");
59+
}
60+
}
61+
62+
static void testScopeOfPatternVariableDeclarations(Object obj) {
63+
if ((obj instanceof String s) && s.length() > 3) {
64+
System.out.println(s);
65+
} else {
66+
System.out.println("Not a string");
67+
}
68+
}
69+
70+
public static void main(String[] args) {
71+
test("a");
72+
test("fooo");
73+
test(1);
74+
test(1L);
75+
instanceOfPattern("abcde");
76+
try {
77+
test(null); // throws NPE
78+
} catch (NullPointerException e) {
79+
e.printStackTrace();
80+
}
81+
testWithNull(null);
82+
testScopeOfPatternVariableDeclarations("a");
83+
testScopeOfPatternVariableDeclarations("long enough");
84+
}
85+
}

0 commit comments

Comments
 (0)