name: port-to-jdk21 description: Port changes from a stage-jdk8-based branch to a stage-based branch, upgrading Java 8 code to Java 21 argument-hint: [source-branch] allowed-tools: Bash, Read, Edit, Write, Grep, Glob user-invocable: true
Port Branch Changes from stage-jdk8 (Java 8) to stage (Java 21)
Port changes from the source branch $ARGUMENTS (based on stage-jdk8) to a new branch based on stage.
Target Branch Naming
The target branch name MUST be derived from the source branch name by removing the _jdk8 suffix:
- Source:
CLIENT-1234_feature_jdk8-> Target:CLIENT-1234_feature - If the source branch doesn't have a
_jdk8suffix, append_jdk21to create the target name:- Source:
bugfix-something-> Target:bugfix-something_jdk21
- Source:
Steps
- Validate the source branch
$ARGUMENTSexists and is based onstage-jdk8. - Analyze the commits on the source branch that are not on
stage-jdk8:git log --oneline stage-jdk8..$ARGUMENTS - Create the target branch off
stage:git checkout stage git pull git checkout -b <target-branch-name> - Cherry-pick the commits from the source branch onto the target branch. If there are conflicts, resolve them with the Java 21 adaptations listed below.
- Adapt the code for Java 21 idioms (see adaptation rules below).
- Purge Maven cache to avoid stale JDK 8 artifacts causing build failures:
mvn dependency:purge-local-repository \ -DreResolve=true \ -DactTransitively=false - Build to verify:
mvn clean install -U
Java 8 to Java 21 Adaptation Rules
When porting code, apply these modernization transformations where appropriate:
Language Features
- Traditional instanceof + cast -> Use pattern matching for instanceof
// Java 8 if (obj instanceof String) { String s = (String) obj; use(s); } // Java 21 if (obj instanceof String s) { use(s); } - Verbose switch statements -> Consider switch expressions where cleaner
// Java 8 String result; switch (x) { case 1: result = "one"; break; case 2: result = "two"; break; default: result = "other"; break; } // Java 21 var result = switch (x) { case 1 -> "one"; case 2 -> "two"; default -> "other"; }; - String concatenation for multiline -> Consider text blocks where appropriate
- Explicit types for local variables -> Use
varwhere the type is obvious from context
API Differences
Collections.unmodifiableList(Arrays.asList(...))-> UseList.of(...)Collections.unmodifiableSet(new HashSet<>(Arrays.asList(...)))-> UseSet.of(...)string.trim().isEmpty()-> Usestring.isBlank()!optional.isPresent()-> Useoptional.isEmpty().collect(Collectors.toList())-> Use.toList()- Traditional I/O patterns -> Consider
Files.readString()/Files.writeString()where appropriate
Project-Specific Differences
- The
stagebranch usesaerospike-client-jdk21artifact instead ofaerospike-client-jdk8 - pom.xml uses
java.version=21instead ofjava.version=1.8/java.api=8 - The
stagebranch may have additional methods (e.g.,estimateKeySize()) not present in jdk8 - Do NOT modify pom.xml java version settings - those are already correct on
stage
Important
- Be conservative with modernization: Only modernize code that is part of the change being ported. Do not refactor surrounding unchanged code.
- Preserve the original commit messages when cherry-picking
- If a file does not exist on
stage, check if the functionality lives in a different file or should be skipped - After all changes, run
mvn clean install -Uand fix any compilation errors