From f09dd139f189906e74daad9fe2aacd2d57546b43 Mon Sep 17 00:00:00 2001 From: Erik Date: Sun, 1 Feb 2026 22:58:56 +0100 Subject: [PATCH] Add migration guides for v0.5.x to v1.0.0, including breaking changes, automated migration patterns, and troubleshooting steps. Update documentation index to include the new migration section. --- docs/README.md | 1 + docs/migration/index.md | 25 +++ docs/migration/v0.5-to-v1.0.md | 348 +++++++++++++++++++++++++++++++++ 3 files changed, 374 insertions(+) create mode 100644 docs/migration/index.md create mode 100644 docs/migration/v0.5-to-v1.0.md diff --git a/docs/README.md b/docs/README.md index 700ede5..56077c0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -148,6 +148,7 @@ Seamlessly integrate Aether Datafixers into Spring Boot applications: ### Support - [Troubleshooting](troubleshooting/index.md) +- [Migration Guide](migration/index.md) - [Common Errors](troubleshooting/common-errors.md) - [FAQ](troubleshooting/faq.md) - [Glossary](appendix/glossary.md) diff --git a/docs/migration/index.md b/docs/migration/index.md new file mode 100644 index 0000000..eccbd6d --- /dev/null +++ b/docs/migration/index.md @@ -0,0 +1,25 @@ +# Migration Guides + +This section contains guides for upgrading between major versions of Aether Datafixers. + +## Available Guides + +| From | To | Guide | +|--------|--------|------------------------------------| +| v0.5.x | v1.0.0 | [Migration Guide](v0.5-to-v1.0.md) | + +## Before You Migrate + +1. **Back up your project** — Create a commit or backup before starting +2. **Read the full guide** — Understand all changes before making modifications +3. **Update dependencies first** — Ensure your build file references the new version +4. **Run tests after** — Verify your migrations still work correctly + +## General Migration Strategy + +1. Update the version in your build file (`pom.xml` or `build.gradle`) +2. Attempt to compile — note all compilation errors +3. Apply automated migration patterns from the guide +4. Fix any remaining issues manually +5. Run your test suite +6. Enable deprecation warnings to catch deprecated API usage diff --git a/docs/migration/v0.5-to-v1.0.md b/docs/migration/v0.5-to-v1.0.md new file mode 100644 index 0000000..c1199e3 --- /dev/null +++ b/docs/migration/v0.5-to-v1.0.md @@ -0,0 +1,348 @@ +# Migration Guide: v0.5.x to v1.0.0 + +This guide helps you migrate your project from Aether Datafixers v0.5.x to v1.0.0. It covers breaking changes, step-by-step migration instructions, and automated migration patterns. + +## Overview + +Version 1.0.0 introduces breaking changes to improve the codec package organization and API clarity. This guide will help you update your codebase with minimal effort. + +| Change Type | Component | Impact | +|-----------------|-------------------------|---------------------------------------------------| +| **Breaking** | Codec package structure | Import statements must be updated | +| **Breaking** | `JacksonOps` rename | Class renamed to `JacksonJsonOps` | +| **Breaking** | `TestData.jackson()` | Method renamed to `TestData.jacksonJson()` | +| **Deprecation** | Rules traversal methods | Single-argument overloads deprecated (still work) | + +--- + +## Breaking Changes + +### 1. Codec Package Restructuring + +The codec module has been reorganized to better reflect the supported formats (JSON, YAML, TOML, XML). + +**Before (v0.5.x):** +```java +import de.splatgames.aether.datafixers.codec.gson.GsonOps; +import de.splatgames.aether.datafixers.codec.jackson.JacksonOps; +``` + +**After (v1.0.0):** +```java +import de.splatgames.aether.datafixers.codec.json.gson.GsonOps; +import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps; +``` + +**Rationale:** The new package structure groups implementations by format type (`json`, `yaml`, `toml`, `xml`) rather than by library. This makes it easier to discover all available JSON implementations and aligns with the YAML/TOML/XML naming conventions. + +**Complete Package Mapping:** + +| Old Package (v0.5.x) | New Package (v1.0.0) | +|----------------------------|-------------------------------------| +| `codec.gson.GsonOps` | `codec.json.gson.GsonOps` | +| `codec.jackson.JacksonOps` | `codec.json.jackson.JacksonJsonOps` | + +### 2. JacksonOps Class Rename + +The `JacksonOps` class has been renamed to `JacksonJsonOps` to distinguish it from other Jackson-based implementations. + +**Before (v0.5.x):** +```java +Dynamic dynamic = new Dynamic<>(JacksonOps.INSTANCE, jsonNode); +``` + +**After (v1.0.0):** +```java +Dynamic dynamic = new Dynamic<>(JacksonJsonOps.INSTANCE, jsonNode); +``` + +**Rationale:** With the introduction of `JacksonYamlOps`, `JacksonTomlOps`, and `JacksonXmlOps`, the generic name `JacksonOps` was ambiguous. The suffix `JsonOps` makes it clear which format is being used. + +### 3. TestData Method Rename + +The `TestData.jackson()` method has been renamed to `TestData.jacksonJson()`. + +**Before (v0.5.x):** +```java +Dynamic testData = TestData.jackson() + .put("name", "Alice") + .put("level", 42) + .build(); +``` + +**After (v1.0.0):** +```java +Dynamic testData = TestData.jacksonJson() + .put("name", "Alice") + .put("level", 42) + .build(); +``` + +**Rationale:** Consistency with `jacksonYaml()`, `jacksonToml()`, and `jacksonXml()` methods. + +--- + +## Deprecations (Non-Breaking) + +### Rules Traversal Methods + +The single-argument overloads of traversal methods are deprecated but **not removed**. Your code will still compile and run, but you'll see deprecation warnings. + +**Deprecated Methods:** +- `Rules.all(rule)` — use `Rules.all(ops, rule)` +- `Rules.one(rule)` — use `Rules.one(ops, rule)` +- `Rules.everywhere(rule)` — use `Rules.everywhere(ops, rule)` +- `Rules.bottomUp(rule)` — use `Rules.bottomUp(ops, rule)` +- `Rules.topDown(rule)` — use `Rules.topDown(ops, rule)` + +**Why migrate?** The deprecated methods are **no-ops** that don't actually traverse children. They exist only for API compatibility. To get proper child traversal behavior, you must provide a `DynamicOps` instance. + +**Before (deprecated):** +```java +TypeRewriteRule rule = Rules.everywhere( + Rules.renameField("player", "name", "username") +); +``` + +**After (recommended):** +```java +TypeRewriteRule rule = Rules.everywhere(GsonOps.INSTANCE, + Rules.renameField("player", "name", "username") +); +``` + +--- + +## Automated Migration + +### IntelliJ IDEA (Regex Search & Replace) + +Use **Edit → Find → Replace in Files** (Ctrl+Shift+R / Cmd+Shift+R) with **Regex** enabled. + +#### GsonOps Import +- **Find:** `import de\.splatgames\.aether\.datafixers\.codec\.gson\.GsonOps;` +- **Replace:** `import de.splatgames.aether.datafixers.codec.json.gson.GsonOps;` + +#### JacksonOps Import and Class Name +- **Find:** `import de\.splatgames\.aether\.datafixers\.codec\.jackson\.JacksonOps;` +- **Replace:** `import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps;` + +Then replace all usages: +- **Find:** `JacksonOps\.INSTANCE` +- **Replace:** `JacksonJsonOps.INSTANCE` + +And the type reference: +- **Find:** `JacksonOps(?!Json)` +- **Replace:** `JacksonJsonOps` + +#### TestData.jackson() +- **Find:** `TestData\.jackson\(\)` +- **Replace:** `TestData.jacksonJson()` + +#### Rules Methods (Optional - for deprecation cleanup) +- **Find:** `Rules\.(all|one|everywhere|bottomUp|topDown)\((?!.*DynamicOps)(\w+)\)` +- **Replace:** `Rules.$1(GsonOps.INSTANCE, $2)` + +**Note:** The Rules regex assumes you want to use `GsonOps.INSTANCE`. Adjust the replacement if you use a different `DynamicOps` implementation. + +--- + +### VS Code (Regex Search & Replace) + +Use **Edit → Replace in Files** (Ctrl+Shift+H / Cmd+Shift+H) with **Regex** enabled (Alt+R). + +The same patterns work in VS Code: + +| Find | Replace | +|--------------------------------------------------------------------------|-----------------------------------------------------------------------------| +| `import de\.splatgames\.aether\.datafixers\.codec\.gson\.GsonOps;` | `import de.splatgames.aether.datafixers.codec.json.gson.GsonOps;` | +| `import de\.splatgames\.aether\.datafixers\.codec\.jackson\.JacksonOps;` | `import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps;` | +| `JacksonOps\.INSTANCE` | `JacksonJsonOps.INSTANCE` | +| `TestData\.jackson\(\)` | `TestData.jacksonJson()` | + +--- + +### Command Line (sed) + +For batch migration across multiple files: + +```bash +# GsonOps import +find . -name "*.java" -exec sed -i 's/import de\.splatgames\.aether\.datafixers\.codec\.gson\.GsonOps;/import de.splatgames.aether.datafixers.codec.json.gson.GsonOps;/g' {} + + +# JacksonOps import +find . -name "*.java" -exec sed -i 's/import de\.splatgames\.aether\.datafixers\.codec\.jackson\.JacksonOps;/import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps;/g' {} + + +# JacksonOps class name +find . -name "*.java" -exec sed -i 's/JacksonOps\.INSTANCE/JacksonJsonOps.INSTANCE/g' {} + +find . -name "*.java" -exec sed -i 's/JacksonOps\([^J]\)/JacksonJsonOps\1/g' {} + + +# TestData.jackson() +find . -name "*.java" -exec sed -i 's/TestData\.jackson()/TestData.jacksonJson()/g' {} + +``` + +**macOS Note:** Use `sed -i ''` instead of `sed -i` on macOS. + +--- + +### PowerShell (Windows) + +```powershell +# GsonOps import +Get-ChildItem -Recurse -Filter *.java | ForEach-Object { + (Get-Content $_.FullName) -replace 'import de\.splatgames\.aether\.datafixers\.codec\.gson\.GsonOps;', 'import de.splatgames.aether.datafixers.codec.json.gson.GsonOps;' | Set-Content $_.FullName +} + +# JacksonOps import +Get-ChildItem -Recurse -Filter *.java | ForEach-Object { + (Get-Content $_.FullName) -replace 'import de\.splatgames\.aether\.datafixers\.codec\.jackson\.JacksonOps;', 'import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps;' | Set-Content $_.FullName +} + +# JacksonOps class name +Get-ChildItem -Recurse -Filter *.java | ForEach-Object { + (Get-Content $_.FullName) -replace 'JacksonOps\.INSTANCE', 'JacksonJsonOps.INSTANCE' | Set-Content $_.FullName +} + +# TestData.jackson() +Get-ChildItem -Recurse -Filter *.java | ForEach-Object { + (Get-Content $_.FullName) -replace 'TestData\.jackson\(\)', 'TestData.jacksonJson()' | Set-Content $_.FullName +} +``` + +--- + +## Verification + +### Step 1: Compile-Time Verification + +After applying the migrations, rebuild your project: + +```bash +mvn clean compile +``` + +or + +```bash +./gradlew clean compileJava +``` + +**Expected:** No compilation errors. If you see import errors, you may have missed some files. + +### Step 2: Check for Deprecation Warnings + +Enable deprecation warnings to identify remaining deprecated API usage: + +**Maven:** +```xml + + org.apache.maven.plugins + maven-compiler-plugin + + + -Xlint:deprecation + + + +``` + +**Gradle:** +```groovy +tasks.withType(JavaCompile) { + options.compilerArgs << "-Xlint:deprecation" +} +``` + +Look for warnings like: +``` +warning: [deprecation] all(TypeRewriteRule) in Rules has been deprecated +``` + +These indicate deprecated `Rules` methods that should be updated to include `DynamicOps`. + +### Step 3: Run Tests + +Execute your test suite to verify runtime behavior: + +```bash +mvn test +``` + +or + +```bash +./gradlew test +``` + +### Step 4: Manual Spot Check + +Verify critical migration paths in your application: + +1. Load sample data from v0.5.x +2. Run migrations through your `DataFixer` +3. Verify output matches expected format +4. Check logs for any unexpected warnings + +--- + +## Troubleshooting + +### "Cannot resolve symbol 'JacksonOps'" + +You updated the import but not all usages of the class name. + +**Solution:** Replace `JacksonOps` with `JacksonJsonOps` throughout your code. + +### "Cannot resolve symbol 'GsonOps'" after migration + +Verify your import statement is: +```java +import de.splatgames.aether.datafixers.codec.json.gson.GsonOps; +``` + +Not the old path: +```java +import de.splatgames.aether.datafixers.codec.gson.GsonOps; +``` + +### Rules not traversing children + +If your `Rules.everywhere()`, `Rules.topDown()`, or similar methods seem to not transform nested data, you're likely using the deprecated single-argument overload. + +**Solution:** Add a `DynamicOps` parameter: +```java +// Before (deprecated, doesn't traverse children) +Rules.everywhere(myRule) + +// After (correct behavior) +Rules.everywhere(GsonOps.INSTANCE, myRule) +``` + +### "TestData.jackson() not found" + +The method was renamed. + +**Solution:** Replace `TestData.jackson()` with `TestData.jacksonJson()`. + +--- + +## Summary Checklist + +- [ ] Update `codec.gson.GsonOps` imports to `codec.json.gson.GsonOps` +- [ ] Update `codec.jackson.JacksonOps` imports to `codec.json.jackson.JacksonJsonOps` +- [ ] Replace `JacksonOps` class references with `JacksonJsonOps` +- [ ] Replace `TestData.jackson()` with `TestData.jacksonJson()` +- [ ] (Optional) Update deprecated `Rules` methods to include `DynamicOps` +- [ ] Rebuild and verify no compilation errors +- [ ] Run test suite +- [ ] Enable deprecation warnings and address remaining issues + +--- + +## Need Help? + +If you encounter issues during migration: + +- Check the [FAQ](../troubleshooting/faq.md) for common questions +- Review [Common Errors](../troubleshooting/common-errors.md) for error messages +- File an issue at [GitHub Issues](https://github.com/aether-framework/aether-datafixers/issues)