|
| 1 | +# json-java21 Module AGENTS.md |
| 2 | + |
| 3 | +## Purpose |
| 4 | +This module backports the upstream OpenJDK sandbox `java.util.json` API to Java 21. |
| 5 | + |
| 6 | +## Upstream Source |
| 7 | +- Repository: https://github.com/openjdk/jdk-sandbox |
| 8 | +- Branch: `json` (NOT master!) |
| 9 | +- Base path: `src/java.base/share/classes/` |
| 10 | +- Public API: `java/util/json/*.java` |
| 11 | +- Internal implementation: `jdk/internal/util/json/*.java` |
| 12 | + |
| 13 | +## CRITICAL WARNING |
| 14 | + |
| 15 | +**DO NOT DOWNLOAD THE REPOSITORY ZIP FILE!** |
| 16 | + |
| 17 | +The jdk-sandbox repository is MASSIVE (the entire JDK). We only need ~19 small Java files. |
| 18 | + |
| 19 | +**ALWAYS fetch individual files using raw GitHub URLs one at a time.** |
| 20 | + |
| 21 | +## Sync Process |
| 22 | + |
| 23 | +### Step 1: Prepare Fresh Download Area |
| 24 | +```bash |
| 25 | +rm -rf .tmp/upstream-sync |
| 26 | +mkdir -p .tmp/upstream-sync/java/util/json |
| 27 | +mkdir -p .tmp/upstream-sync/jdk/internal/util/json |
| 28 | +``` |
| 29 | + |
| 30 | +### Step 2: Fetch Upstream Sources (ONE FILE AT A TIME) |
| 31 | + |
| 32 | +**CRITICAL: Fetch each file individually using curl or wget with the raw GitHub URL.** |
| 33 | + |
| 34 | +The URL pattern is: |
| 35 | +``` |
| 36 | +https://raw.githubusercontent.com/openjdk/jdk-sandbox/json/src/java.base/share/classes/<path> |
| 37 | +``` |
| 38 | + |
| 39 | +Note the branch is `json` in the URL path (NOT `refs/heads/json`, just `json`). |
| 40 | + |
| 41 | +#### Public API files (~10 files): |
| 42 | +```bash |
| 43 | +curl -o .tmp/upstream-sync/java/util/json/Json.java \ |
| 44 | + "https://raw.githubusercontent.com/openjdk/jdk-sandbox/json/src/java.base/share/classes/java/util/json/Json.java" |
| 45 | + |
| 46 | +curl -o .tmp/upstream-sync/java/util/json/JsonArray.java \ |
| 47 | + "https://raw.githubusercontent.com/openjdk/jdk-sandbox/json/src/java.base/share/classes/java/util/json/JsonArray.java" |
| 48 | + |
| 49 | +... |
| 50 | +``` |
| 51 | + |
| 52 | +#### Internal implementation files (~9 files): |
| 53 | +```bash |
| 54 | +curl -o .tmp/upstream-sync/jdk/internal/util/json/JsonArrayImpl.java \ |
| 55 | + "https://raw.githubusercontent.com/openjdk/jdk-sandbox/json/src/java.base/share/classes/jdk/internal/util/json/JsonArrayImpl.java" |
| 56 | + |
| 57 | +curl -o .tmp/upstream-sync/jdk/internal/util/json/JsonBooleanImpl.java \ |
| 58 | + "https://raw.githubusercontent.com/openjdk/jdk-sandbox/json/src/java.base/share/classes/jdk/internal/util/json/JsonBooleanImpl.java" |
| 59 | + |
| 60 | +... |
| 61 | +``` |
| 62 | + |
| 63 | +#### Verify downloads succeeded: |
| 64 | +```bash |
| 65 | +# Should show X files (whatever is currently upstream) |
| 66 | +ls -la .tmp/upstream-sync/java/util/json/ |
| 67 | + |
| 68 | +# Should show Y files (whatever is currently upstream) |
| 69 | +ls -la .tmp/upstream-sync/jdk/internal/util/json/ |
| 70 | + |
| 71 | +# Check none are empty or HTML error pages |
| 72 | +wc -l .tmp/upstream-sync/java/util/json/*.java |
| 73 | +wc -l .tmp/upstream-sync/jdk/internal/util/json/*.java |
| 74 | +``` |
| 75 | + |
| 76 | +### Step 3: Create Backported Structure |
| 77 | +Create parallel structure in `.tmp/backported/` with our package names: |
| 78 | + |
| 79 | +```bash |
| 80 | +mkdir -p .tmp/backported/jdk/sandbox/java/util/json |
| 81 | +mkdir -p .tmp/backported/jdk/sandbox/internal/util/json |
| 82 | +``` |
| 83 | + |
| 84 | +### Step 4: Apply Backporting Transformations |
| 85 | +For each downloaded file, apply these transformations using Python heredocs (not sed/perl for multi-line): |
| 86 | + |
| 87 | +#### 4.1 Package Renaming |
| 88 | +- `java.util.json` → `jdk.sandbox.java.util.json` |
| 89 | +- `jdk.internal.util.json` → `jdk.sandbox.internal.util.json` |
| 90 | + |
| 91 | +#### 4.2 Remove Preview Feature Annotations |
| 92 | +Delete lines containing: |
| 93 | +- `import jdk.internal.javac.PreviewFeature;` |
| 94 | +- `@PreviewFeature(feature = PreviewFeature.Feature.JSON)` |
| 95 | + |
| 96 | +#### 4.3 StableValue Polyfill |
| 97 | +Upstream uses `jdk.internal.lang.stable.StableValue` which is not available in Java 21. |
| 98 | + |
| 99 | +**Replace imports:** |
| 100 | +- `import jdk.internal.lang.stable.StableValue;` → (remove, our polyfill is package-local) |
| 101 | + |
| 102 | +**The polyfill `StableValue.java`** (already in our repo) provides: |
| 103 | +- `StableValue.of()` - creates empty holder |
| 104 | +- `orElse(T defaultValue)` - returns value or default |
| 105 | +- `orElseSet(Supplier<T>)` - lazy initialization with double-checked locking |
| 106 | +- `setOrThrow(T)` - one-time set |
| 107 | +- `StableValue.supplier(Supplier<T>)` - memoizing supplier wrapper |
| 108 | + |
| 109 | +This file is NOT from upstream and must be preserved during sync. |
| 110 | + |
| 111 | +#### 4.4 DO NOT Convert JavaDoc to JEP 467 Markdown |
| 112 | +If upstream uses `/** ... */` style, DO NOT convert them to our `/// ...` format; we will not edit the upstream files more than the absolute minimum to get them to run on Java 21. |
| 113 | + |
| 114 | +#### 4.5 Add JsonAssertionException (Our Addition) |
| 115 | +The file `JsonAssertionException.java` is a local addition not in upstream. Preserve it. |
| 116 | + |
| 117 | +#### 4.6 Preserve Demo File |
| 118 | +The file `jdk/sandbox/demo/JsonDemo.java` is a local addition for demonstration purposes. Preserve it. Fix it. |
| 119 | + |
| 120 | +### Step 5: Verify Compilation with javac |
| 121 | +Before copying to the main source tree, verify the backported code compiles: |
| 122 | + |
| 123 | +```bash |
| 124 | +# Find all Java files in the backported structure |
| 125 | +find .tmp/backported -name "*.java" > .tmp/sources.txt |
| 126 | + |
| 127 | +# Also include our polyfill and local additions |
| 128 | +echo "json-java21/src/main/java/jdk/sandbox/internal/util/json/StableValue.java" >> .tmp/sources.txt |
| 129 | +echo "json-java21/src/main/java/jdk/sandbox/java/util/json/JsonAssertionException.java" >> .tmp/sources.txt |
| 130 | + |
| 131 | +# Compile with Java 21 |
| 132 | +javac --release 21 -d .tmp/classes @.tmp/sources.txt |
| 133 | +``` |
| 134 | + |
| 135 | +### Step 6: Copy to Source Tree (After Verification) |
| 136 | + |
| 137 | +Only after javac succeeds: |
| 138 | + |
| 139 | +```bash |
| 140 | +# Backup current sources (optional) |
| 141 | +cp -r json-java21/src/main/java/jdk/sandbox .tmp/backup-sandbox |
| 142 | + |
| 143 | +# Copy backported files (excluding our local additions) |
| 144 | +cp .tmp/backported/jdk/sandbox/java/util/json/*.java \ |
| 145 | + json-java21/src/main/java/jdk/sandbox/java/util/json/ |
| 146 | + |
| 147 | +cp .tmp/backported/jdk/sandbox/internal/util/json/*.java \ |
| 148 | + json-java21/src/main/java/jdk/sandbox/internal/util/json/ |
| 149 | + |
| 150 | +# Restore our local additions if overwritten |
| 151 | +# (StableValue.java, JsonAssertionException.java should not be in backported/) |
| 152 | +``` |
| 153 | + |
| 154 | +The file `jdk/sandbox/demo/JsonDemo.java` should be the example code in our README.md, as it may have changed to reflect upstream changes. You MUST update the README.md to include examples of the upgraded code in this file, which you must MANUALLY VERIFY IS GOOD post-upgrade. |
| 155 | + |
| 156 | +### Step 7: Full Maven Build |
| 157 | + |
| 158 | +```bash |
| 159 | +$(command -v mvnd || command -v mvn || command -v ./mvnw) clean test -pl json-java21 -Djava.util.logging.ConsoleHandler.level=INFO |
| 160 | +``` |
| 161 | + |
| 162 | +## Files That Are Local Additions (Preserve During Sync) |
| 163 | + |
| 164 | +| File | Purpose | |
| 165 | +|------|---------| |
| 166 | +| `jdk/sandbox/internal/util/json/StableValue.java` | Java 21 polyfill for future JDK StableValue API | |
| 167 | +| `jdk/sandbox/java/util/json/JsonAssertionException.java` | Custom exception for type assertion errors | |
| 168 | +| `jdk/sandbox/demo/JsonDemo.java` | Demonstration/example code | |
| 169 | + |
| 170 | +## Transformation Example |
| 171 | + |
| 172 | +**Upstream `JsonStringImpl.java` (excerpt):** |
| 173 | +```java |
| 174 | +package jdk.internal.util.json; |
| 175 | + |
| 176 | +import java.util.json.JsonString; |
| 177 | +import jdk.internal.lang.stable.StableValue; |
| 178 | + |
| 179 | +public final class JsonStringImpl implements JsonString, JsonValueImpl { |
| 180 | + private final StableValue<String> jsonStr = StableValue.of(); |
| 181 | + // ... |
| 182 | +} |
| 183 | +``` |
| 184 | + |
| 185 | +**Backported version:** |
| 186 | +```java |
| 187 | +package jdk.sandbox.internal.util.json; |
| 188 | + |
| 189 | +import jdk.sandbox.java.util.json.JsonString; |
| 190 | +// StableValue is package-local, no import needed |
| 191 | + |
| 192 | +public final class JsonStringImpl implements JsonString, JsonValueImpl { |
| 193 | + private final StableValue<String> jsonStr = StableValue.of(); |
| 194 | + // ... |
| 195 | +} |
| 196 | +``` |
| 197 | + |
| 198 | +## Troubleshooting |
| 199 | + |
| 200 | +### Compilation Errors After Sync |
| 201 | +1. Check package names are correctly transformed |
| 202 | +2. Verify StableValue polyfill is present |
| 203 | +3. Check for new upstream APIs that may need additional polyfills |
| 204 | + |
| 205 | +### Test Failures After Sync |
| 206 | +1. Run with verbose logging: `-Djava.util.logging.ConsoleHandler.level=FINE` |
| 207 | +2. Check if upstream changed method signatures |
| 208 | +3. Review upstream commit history for breaking changes |
0 commit comments