Add jep513 module: flexible constructor bodies on JDK 25 and 27

Runnable sources, broken examples and captured transcripts for the ankurm.com JEP 513 article, including the JDK 25 vs 27 compiler wording differences.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01TF9JWFvJSNm6HVzswzZU5a
This commit is contained in:
Claude
2026-09-24 10:42:36 +00:00
parent e0cb6e83e2
commit 2ebea58d39
30 changed files with 510 additions and 0 deletions
Executable
+48
View File
@@ -0,0 +1,48 @@
#!/usr/bin/env bash
# JEP 513 (Flexible Constructor Bodies): final in JDK 25, no --enable-preview.
# Regenerates every file in output/. JDK25=/path JDK27=/path [JDK21=/path] ./run.sh
set -uo pipefail
unset JAVA_TOOL_OPTIONS
HERE="$(cd "$(dirname "$0")" && pwd)"
JDK25="${JDK25:-/opt/jdks/jdk-25.0.4.1+1}"; JDK27="${JDK27:-/opt/jdks/jdk27}"; JDK21="${JDK21:-}"
OUT="$HERE/output"; mkdir -p "$OUT"; B="$(mktemp -d)"; trap 'rm -rf "$B"' EXIT
cd "$HERE"
v() { "$1/bin/java" -version 2>&1 | sed -n 2p; }
# compile SRC with JDK, then run CLASS from it; prints a header naming the JDK
cr() { local jdk="$1" src="$2" cls="$3"; local o="$B/$(basename "$jdk")-$cls"; mkdir -p "$o"
echo "\$ javac $src && java $cls ($(v "$jdk"))"
"$jdk/bin/javac" -d "$o" "$src" 2>&1 && "$jdk/bin/java" -cp "$o" "$cls" 2>&1; }
{ cr "$JDK25" src/ValidateBeforeSuper.java ValidateBeforeSuper; echo; cr "$JDK27" src/ValidateBeforeSuper.java ValidateBeforeSuper
} > "$OUT/01-validate-before-super.txt"
{ cr "$JDK25" src/BeforeJava25.java BeforeJava25
[ -n "$JDK21" ] && { echo; cr "$JDK21" src/BeforeJava25.java BeforeJava25; }
} > "$OUT/02-the-old-workaround.txt"
{ [ -n "$JDK21" ] && { cr "$JDK21" broken/OnJdk21.java OnJdk21; echo; }
cr "$JDK25" broken/OnJdk21.java OnJdk21; echo; cr "$JDK27" broken/OnJdk21.java OnJdk21
} > "$OUT/03-same-file-on-21-25-27.txt"
{ cr "$JDK25" src/OverridableCall.java OverridableCall; } > "$OUT/04-overridable-call-bug-and-fix.txt"
{ cr "$JDK25" src/ParseThenSuper.java ParseThenSuper; echo; cr "$JDK25" src/TryInPrologue.java TryInPrologue; echo; cr "$JDK25" src/ThisChaining.java ThisChaining
} > "$OUT/05-prologue-in-practice.txt"
{ o="$B/bc"; mkdir -p "$o"; "$JDK25/bin/javac" -d "$o" src/PrologueBytecode.java 2>&1
echo "\$ javap -c -p 'PrologueBytecode\$Child' ($(v "$JDK25"))"; "$JDK25/bin/javap" -c -p -cp "$o" 'PrologueBytecode$Child' 2>&1 | sed -n '2,$p'
} > "$OUT/06-bytecode.txt"
# the rules that did not go away: same source, both JDKs, because the wording changed between 25 and 27
{ for f in ReadFieldBeforeSuper CallMethodBeforeSuper PassThisBeforeSuper ReadFinalBeforeAssign InnerOuterThis NewInnerBeforeSuper AssignFieldWithInitializer AssignInheritedField ReturnBeforeSuper SuperInBranch TwoSuperCalls; do
for j in "$JDK25" "$JDK27"; do
echo "\$ javac broken/$f.java ($(v "$j" | sed 's/.*Temurin-//;s/ (build.*//'))"
"$j/bin/javac" -d "$B/x" broken/$f.java 2>&1 | grep -E 'error|warning' | sed 's/^broken\///'
done; echo
done
} > "$OUT/07-still-illegal-25-vs-27.txt"
# 08 - the language level matters: compiling this source for an older target from JDK 25
{ for r in 21 24 25; do echo "\$ javac --release $r broken/OnJdk21.java ($(v "$JDK25" | sed 's/.*Temurin-//;s/ (build.*//'))"
"$JDK25/bin/javac" --release $r -d "$B/r$r" broken/OnJdk21.java 2>&1 | grep -v '^Note:' | sed 's/^broken\///'; echo "exit=${PIPESTATUS[0]}"; echo; done
} > "$OUT/08-release-levels.txt"
echo "wrote $OUT"