[java] Update impl for "Flexible Constructor Bodies"

This commit is contained in:
Andreas Dangel
2024-07-12 11:16:01 +02:00
parent 20750f9591
commit bb40b754a2
5 changed files with 464 additions and 3 deletions

View File

@ -142,8 +142,9 @@ public class LanguageLevelChecker<T> {
/**
* Statements before super
* @see <a href="https://openjdk.org/jeps/447">JEP 447: Statements before super(...) (Preview)</a> (Java 22)
* @see <a href="https://openjdk.org/jeps/482">JEP 482: Flexible Constructor Bodies (Second Preview)</a> (Java 23)
*/
STATEMENTS_BEFORE_SUPER(22, 22, false),
FLEXIBLE_CONSTRUCTOR_BODIES(22, 23, false),
; // SUPPRESS CHECKSTYLE enum trailing semi is awesome
@ -697,7 +698,7 @@ public class LanguageLevelChecker<T> {
super.visit(node, data);
if (node.getBody().descendants(ASTExplicitConstructorInvocation.class).nonEmpty()) {
if (!(node.getBody().getFirstChild() instanceof ASTExplicitConstructorInvocation)) {
check(node, PreviewFeature.STATEMENTS_BEFORE_SUPER, data);
check(node, PreviewFeature.FLEXIBLE_CONSTRUCTOR_BODIES, data);
}
}
return null;

View File

@ -101,6 +101,6 @@ class Java22PreviewTreeDumpTest extends BaseJavaTreeDumpTest {
@Test
void jep447StatementsBeforeSuperBeforeJava22Preview() {
ParseException thrown = assertThrows(ParseException.class, () -> java22.parseResource("Jep447_StatementsBeforeSuper.java"));
assertThat(thrown.getMessage(), containsString("Statements before super is a preview feature of JDK 22, you should select your language version accordingly"));
assertThat(thrown.getMessage(), containsString("Flexible constructor bodies is a preview feature of JDK 22, you should select your language version accordingly"));
}
}

View File

@ -48,4 +48,14 @@ class Java23PreviewTreeDumpTest extends BaseJavaTreeDumpTest {
doTest("Jep477_ImplicitlyDeclaredClassesAndInstanceMainMethods2");
}
@Test
void jep482FlexibleConstructorBodies() {
doTest("Jep482_FlexibleConstructorBodies");
}
@Test
void jep482FlexibleConstructorBodiesBeforeJava23Preview() {
ParseException thrown = assertThrows(ParseException.class, () -> java23.parseResource("Jep482_FlexibleConstructorBodies.java"));
assertThat(thrown.getMessage(), containsString("Flexible constructor bodies is a preview feature of JDK 23, you should select your language version accordingly"));
}
}

View File

@ -0,0 +1,106 @@
/*
* BSD-style license; for more info see http://pmd.sourceforge.net/license.html
*/
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.cert.Certificate;
import java.security.interfaces.DSAPublicKey;
import java.security.interfaces.RSAKey;
/**
* @see <a href="https://openjdk.org/jeps/447">JEP 447: Statements before super(...) (Preview)</a> (Java 22)
* @see <a href="https://openjdk.org/jeps/482">JEP 482: Flexible Constructor Bodies (Second Preview)</a> (Java 23)
*/
class Jep482_FlexibleConstructorBodies {
// To test backwards compatibility - "normal" explicit constructor invocation
public static class Old {
public Old() {
super();
}
}
// Example: Validating superclass constructor arguments
public static class PositiveBigInteger extends BigInteger {
public PositiveBigInteger(long value) {
if (value <= 0)
throw new IllegalArgumentException("non-positive value");
final String valueAsString = String.valueOf(value);
super(valueAsString);
}
}
// Example: Preparing superclass constructor arguments
public static class Super {
public Super(byte[] bytes) {}
}
public class Sub extends Super {
public Sub(Certificate certificate) {
var publicKey = certificate.getPublicKey();
if (publicKey == null)
throw new IllegalArgumentException("null certificate");
final byte[] byteArray = switch (publicKey) {
case RSAKey rsaKey -> rsaKey.toString().getBytes(StandardCharsets.UTF_8);
case DSAPublicKey dsaKey -> dsaKey.toString().getBytes(StandardCharsets.UTF_8);
default -> new byte[0];
};
super(byteArray);
}
}
// Example: Sharing superclass constructor arguments
public static class F {}
public static class Super2 {
public Super2(F f1, F f2) {}
}
public class Sub2 extends Super2 {
public Sub2(int i) {
var f = new F();
super(f, f);
// ... i ...
}
}
// Example with records
public record Range(int lo, int hi) {
public Range(int lo, int hi, int maxDistance) {
if (lo > hi)
throw new IllegalArgumentException(String.format("(%d,%d)", lo, hi));
if (hi - lo > maxDistance)
throw new IllegalArgumentException(String.format("(%d,%d,%d", lo, hi, maxDistance));
this(lo, hi);
}
}
// Example with enum
public enum Color {
BLUE(1);
private Color() {
}
private Color(int a) {
if (a < 0) throw new IllegalArgumentException();
this();
};
}
// Example for Early assignment to fields (new with Java 23 preview)
public static class EarlyAssignmentToFieldsSuper {
EarlyAssignmentToFieldsSuper() { overriddenMethod(); }
void overriddenMethod() { System.out.println("hello"); }
}
public static class EarlyAssignmentToFieldsSub extends EarlyAssignmentToFieldsSuper {
final int x;
EarlyAssignmentToFieldsSub(int x) {
this.x = x; // Initialize the field
super(); // Then invoke the Super constructor explicitly
}
@Override
void overriddenMethod() { System.out.println(x); }
}
}