Releases: aether-framework/aether-datafixers
🚀 Aether Datafixers v0.4.0 — Spring Boot Integration & Multi-Format DynamicOps
Spring Boot auto-configuration with fluent MigrationService API, Actuator integration, and comprehensive multi-format support for YAML, TOML, and XML.
🎯 Highlights in v0.4.0
- ✅ Spring Boot Starter — New
aether-datafixers-spring-boot-startermodule with auto-configuration, fluentMigrationServiceAPI, multi-domain support, Actuator health/info/endpoints, and Micrometer metrics - ✅ Multi-Format DynamicOps — New DynamicOps implementations for YAML (SnakeYAML, Jackson), TOML (Jackson), and XML (Jackson)
- ✅ Package Restructuring — Format-first package organization (
codec.json.gson,codec.yaml.jackson, etc.) - ✅ Comprehensive Documentation — New Spring Boot integration docs and codec format guides
📦 Installation
Tip
All Aether artifacts are available on Maven Central — no extra repository required.
Maven
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
<version>0.4.0</version>
</dependency>Using the BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-bom</artifactId>
<version>0.4.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No version needed -->
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
</dependency>
</dependencies>Gradle (Groovy)
dependencies {
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core:0.4.0'
// Or with BOM:
implementation platform('de.splatgames.aether.datafixers:aether-datafixers-bom:0.4.0')
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core'
}Gradle (Kotlin)
dependencies {
implementation("de.splatgames.aether.datafixers:aether-datafixers-core:0.4.0")
// Or with BOM:
implementation(platform("de.splatgames.aether.datafixers:aether-datafixers-bom:0.4.0"))
implementation("de.splatgames.aether.datafixers:aether-datafixers-core")
}🆕 What's New
🍃 Spring Boot Starter Module
New module aether-datafixers-spring-boot-starter for seamless Spring Boot 3.x integration:
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-spring-boot-starter</artifactId>
<version>0.4.0</version>
</dependency>Key Features:
| Feature | Description |
|---|---|
| 🔧 Auto-Configuration | Automatic DataFixer bean creation from DataFixerBootstrap beans |
| 🔄 MigrationService | Fluent API: .migrate(data).from(100).to(200).execute() |
| 🏷️ Multi-Domain | Multiple DataFixers with @Qualifier and .usingDomain("game") |
| 💚 Actuator | Health indicator, info contributor, /actuator/datafixers endpoint |
| 📊 Metrics | Micrometer counters, timers, and distribution summaries |
| ⚡ Async | CompletableFuture support via .executeAsync() |
Quick Start:
@Configuration
public class DataFixerConfig {
@Bean
public DataFixerBootstrap gameBootstrap() {
return new GameDataBootstrap();
}
}
@Service
public class GameService {
private final MigrationService migrationService;
public Dynamic<?> migrateData(Dynamic<?> data, int fromVersion) {
return migrationService
.migrate(data)
.from(fromVersion)
.toLatest()
.execute()
.getData();
}
}Configuration Properties:
aether:
datafixers:
enabled: true
default-format: gson # gson | jackson | jackson_yaml | snakeyaml | jackson_toml | jackson_xml
default-current-version: 200
domains:
game:
current-version: 200
primary: true
actuator:
include-schema-details: true
metrics:
timing: true
counting: true🔌 Multi-Format DynamicOps
New DynamicOps implementations in the codec module:
| Format | Implementation | Data Type | Library |
|---|---|---|---|
| JSON | GsonOps |
JsonElement |
Gson |
| JSON | JacksonJsonOps |
JsonNode |
Jackson |
| YAML | SnakeYamlOps |
Object |
SnakeYAML |
| YAML | JacksonYamlOps |
JsonNode |
Jackson YAML |
| TOML | JacksonTomlOps |
JsonNode |
Jackson TOML |
| XML | JacksonXmlOps |
JsonNode |
Jackson XML |
Example:
// YAML with SnakeYAML (native Java types)
Dynamic<Object> yaml = new Dynamic<>(SnakeYamlOps.INSTANCE, yamlData);
// TOML with Jackson
Dynamic<JsonNode> toml = new Dynamic<>(JacksonTomlOps.INSTANCE, tomlData);
// Cross-format conversion
Dynamic<JsonElement> json = yaml.convert(GsonOps.INSTANCE);⚠️ Breaking Change: Package Restructuring
The codec module now uses format-first package organization:
Old:
import de.splatgames.aether.datafixers.codec.gson.GsonOps;
import de.splatgames.aether.datafixers.codec.jackson.JacksonOps;New:
import de.splatgames.aether.datafixers.codec.json.gson.GsonOps;
import de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps;
import de.splatgames.aether.datafixers.codec.yaml.snakeyaml.SnakeYamlOps;
import de.splatgames.aether.datafixers.codec.yaml.jackson.JacksonYamlOps;
import de.splatgames.aether.datafixers.codec.toml.jackson.JacksonTomlOps;
import de.splatgames.aether.datafixers.codec.xml.jackson.JacksonXmlOps;📝 Changelog
New in 0.4.0
- Spring Boot Starter with auto-configuration and MigrationService
- Actuator health indicator, info contributor, and custom endpoint
- Micrometer metrics for migration success/failure/duration
- Multi-domain DataFixer support with
@Qualifier - SnakeYamlOps for YAML (native Java types)
- JacksonYamlOps for YAML (Jackson dataformat)
- JacksonTomlOps for TOML
- JacksonXmlOps for XML
- Format-first package restructuring in codec module
- Comprehensive Spring Boot and codec documentation
Full Changelog: v0.3.0...v0.4.0
🗺️ Roadmap (next)
- v0.5.0 (API freeze candidate)
- API stabilization pass — Naming/packaging cleanup + deprecations completed
- Compatibility checks in CI — Binary/source compatibility guardrails for public API
- Hardened error model — Consistent exception types + structured error details
- Release readiness — Final review of docs/examples against frozen API
📜 License
MIT — see LICENSE.
🚀 Aether Datafixers v0.3.0 — CLI, Schema Tools, and Convention Validation
Command-line interface for batch migrations, schema analysis tools, and naming convention validation.
🎯 Highlights in v0.3.0
- ✅ CLI Module — New
aether-datafixers-climodule for migrating and validating data files from the command line with batch processing and reports. - ✅ Schema Tools Module — New
aether-datafixers-schema-toolsmodule for schema diffing, migration analysis, validation, and type introspection. - ✅ Fix Coverage Analysis — Detect schema changes without corresponding DataFixes to ensure complete migration coverage.
- ✅ Convention Checking — Enforce naming conventions for types, fields, schema classes, and fix classes.
📦 Installation
Tip
All Aether artifacts are available on Maven Central — no extra repository required.
Maven
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
<version>0.3.0</version>
</dependency>Using the BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-bom</artifactId>
<version>0.3.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No version needed -->
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
</dependency>
</dependencies>Gradle (Groovy)
dependencies {
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core:0.3.0'
// Or with BOM:
implementation platform('de.splatgames.aether.datafixers:aether-datafixers-bom:0.3.0')
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core'
}Gradle (Kotlin)
dependencies {
implementation("de.splatgames.aether.datafixers:aether-datafixers-core:0.3.0")
// Or with BOM:
implementation(platform("de.splatgames.aether.datafixers:aether-datafixers-bom:0.3.0"))
implementation("de.splatgames.aether.datafixers:aether-datafixers-core")
}🆕 What's New
🖥️ CLI Module
New module aether-datafixers-cli for command-line data migration:
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-cli</artifactId>
<version>0.3.0</version>
</dependency>Commands:
| Command | Description |
|---|---|
migrate |
Migrate data files from one schema version to another |
validate |
Check if files need migration without modifying them |
info |
Display version info, available formats, and bootstrap details |
Features:
- Batch processing of multiple files with shell glob expansion
- Auto-detection of source version from configurable data field path
- In-place file modification with automatic
.bakbackup - Output to stdout, file, or directory
- Pretty-printed or compact JSON output
- Migration reports in text or JSON format
- Verbose mode with detailed progress and stack traces
- CI/CD friendly exit codes (0=success, 1=error, 2=migration needed)
Example:
# Migrate a single file
aether-cli migrate --from 100 --to 200 --type player --bootstrap com.example.MyBootstrap input.json
# Migrate with auto-detected version
aether-cli migrate --to 200 --type player --version-field dataVersion --bootstrap com.example.MyBootstrap input.json
# Validate files (check without modifying)
aether-cli validate --to 200 --type player --bootstrap com.example.MyBootstrap *.json
# Show available formats and bootstrap info
aether-cli info --formats
aether-cli info --bootstrap com.example.MyBootstrap🔧 Schema Tools Module
New module aether-datafixers-schema-tools for schema analysis and validation:
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-schema-tools</artifactId>
<version>0.3.0</version>
</dependency>Schema Diffing
Compare schemas between versions to see what changed:
SchemaDiff diff = SchemaDiffer.compare(schemaV1, schemaV2)
.includeFieldLevel(true)
.diff();
// Check results
diff.addedTypes(); // Types new in schemaV2
diff.removedTypes(); // Types removed from schemaV1
diff.commonTypes(); // Types in both schemas
diff.typeDiffs(); // Field-level changes for common typesMigration Analysis
Analyze migration paths and detect coverage gaps:
FixCoverage coverage = MigrationAnalyzer.forBootstrap(bootstrap)
.from(100).to(200)
.analyzeCoverage();
// Find schema changes without DataFixes
for (CoverageGap gap : coverage.gaps()) {
System.out.println("Missing fix for: " + gap.type() + " (" + gap.reason() + ")");
}
// Detect orphan fixes (fixes without schema changes)
coverage.orphanFixes();Schema Validation
Validate schema structure and naming conventions:
ValidationResult result = SchemaValidator.forBootstrap(bootstrap)
.validateStructure()
.validateConventions(ConventionRules.STRICT)
.validate();
// Check for issues
for (ValidationIssue issue : result.issues()) {
System.out.println(issue.severity() + ": " + issue.message());
}Convention Checking
Enforce naming conventions:
ConventionChecker checker = ConventionChecker.withRules(ConventionRules.builder()
.typeNamePattern(Pattern.compile("[a-z][a-z0-9_]*")) // snake_case types
.fieldNamePattern(Pattern.compile("[a-z][a-zA-Z0-9]*")) // camelCase fields
.schemaClassPrefix("Schema") // Schema100, Schema200
.fixClassSuffix("Fix") // PlayerNameFix, PositionFix
.build());
List<ValidationIssue> issues = checker.check(bootstrap);Type Introspection
Inspect type structures programmatically:
TypeStructure structure = TypeIntrospector.introspect(type);
// Get all fields with their paths
for (FieldInfo field : structure.fields()) {
System.out.println(field.path() + " : " + field.typeKind());
}
// Compare structures
boolean equal = TypeIntrospector.structurallyEqual(type1, type2);📝 Changelog
New in 0.3.0
- CLI module with migrate, validate, and info commands
- Schema Tools module with diffing, analysis, validation, and introspection
- Fix coverage analysis to detect missing DataFixes
- Convention checking for type, field, and class names
- Format handler SPI with Gson and Jackson implementations
- Comprehensive documentation updates
Full Changelog: v0.2.0...v0.3.0
🗺️ Roadmap (next)
-
v0.4.0
- Spring Boot integration — Auto-configuration for DataFixer in Spring apps
- Extra ops modules — Optional YAML/TOML support (format adapters)
- Debug utilities — Pretty printers / tree diff for Dynamic structures (dev-facing)
-
v0.5.0 (API freeze candidate)
- API stabilization pass — Naming/packaging cleanup + deprecations completed
- Compatibility checks in CI — Binary/source compatibility guardrails for public API
- Hardened error model — Consistent exception types + structured error details
- Release readiness — Final review of docs/examples against frozen API
📜 License
MIT — see LICENSE.
🚀 Aether Datafixers v0.2.0 — Testkit, Extended Rules, Diagnostics, and Performance
Extended rules, testkit module, migration diagnostics, and high-performance APIs.
🎯 Highlights in v0.2.0
- ✅ Testkit Module — New
aether-datafixers-testkitmodule with fluent test data builders, custom AssertJ assertions, and test harnesses for DataFix, Schema, and migration testing. - ✅ Extended Rewrite Rules — Convenience methods for batch operations, field grouping/flattening, path-based operations, and conditional rules.
- ✅ Migration Diagnostics — Opt-in diagnostic system for structured reports with timing, snapshots, and warnings.
- ✅ High-Performance APIs — Batch transformations and single-pass conditionals for optimized migrations.
- ✅ Performance Optimizations — Internal improvements with memoized path parsing, pre-allocated lists, and reduced allocations.
📦 Installation
Tip
All Aether artifacts are available on Maven Central — no extra repository required.
Maven
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
<version>0.2.0</version>
</dependency>Using the BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-bom</artifactId>
<version>0.2.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No version needed -->
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-core</artifactId>
</dependency>
</dependencies>Gradle (Groovy)
dependencies {
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core:0.2.0'
// Or with BOM:
implementation platform('de.splatgames.aether.datafixers:aether-datafixers-bom:0.2.0')
implementation 'de.splatgames.aether.datafixers:aether-datafixers-core'
}Gradle (Kotlin)
dependencies {
implementation("de.splatgames.aether.datafixers:aether-datafixers-core:0.2.0")
// Or with BOM:
implementation(platform("de.splatgames.aether.datafixers:aether-datafixers-bom:0.2.0"))
implementation("de.splatgames.aether.datafixers:aether-datafixers-core")
}🆕 What's New
🧪 Testkit Module
New module aether-datafixers-testkit for testing migrations:
<dependency>
<groupId>de.splatgames.aether.datafixers</groupId>
<artifactId>aether-datafixers-testkit</artifactId>
<version>0.2.0</version>
<scope>test</scope>
</dependency>Features:
TestData— Fluent test data builders for Gson and JacksonAetherAssertions— Custom AssertJ assertions forDynamic,DataResult,TypedDataFixTester— Test harness for individual DataFix implementationsMigrationTester— Test harness for complete migration chainsSchemaTester— Test harness for Schema validationQuickFix— Factory methods for common fix patternsMockSchemas— Factory for mock Schema instancesRecordingContext/AssertingContext— Test contexts
Example:
// Create test data fluently
Dynamic<JsonElement> input = TestData.gson().object()
.put("name", "Alice")
.put("level", 10)
.build();
// Test a DataFix
DataFixTester.forFix(myFix)
.withInput(input)
.forType("player")
.expectOutput(expected)
.verify();
// Test a full migration chain
MigrationTester.forFixer(myFixer)
.forType(PLAYER)
.withInput(v1Data)
.from(1).to(5)
.expectOutput(v5Data)
.verify();📐 Extended Rewrite Rules
New convenience methods in Rules class:
| Rule | Purpose |
|---|---|
dynamicTransform(name, ops, fn) |
Custom Dynamic transformation |
setField(ops, field, value) |
Set field (overwrites existing) |
renameFields(ops, map) |
Batch rename multiple fields |
removeFields(ops, fields...) |
Batch remove multiple fields |
groupFields(ops, target, fields...) |
Group fields into nested object |
flattenField(ops, field) |
Flatten nested object to root |
moveField(ops, source, target) |
Move field between paths |
copyField(ops, source, target) |
Copy field (keeps original) |
transformFieldAt(ops, path, fn) |
Transform at nested path |
renameFieldAt(ops, path, newName) |
Rename at nested path |
removeFieldAt(ops, path) |
Remove at nested path |
addFieldAt(ops, path, value) |
Add at nested path |
ifFieldExists(ops, field, rule) |
Conditional on existence |
ifFieldMissing(ops, field, rule) |
Conditional on absence |
ifFieldEquals(ops, field, value, rule) |
Conditional on value |
Example:
Rules.seq(
Rules.renameFields(ops, Map.of("playerName", "name", "xp", "experience")),
Rules.groupFields(ops, "position", "x", "y", "z"),
Rules.ifFieldMissing(ops, "version", Rules.setField(ops, "version", d -> d.createInt(1)))
)📊 Migration Diagnostics
New opt-in diagnostic system for capturing structured reports:
API:
DiagnosticOptions— Configuration for diagnostic captureDiagnosticContext— Context interface for diagnostic migrationsMigrationReport— Immutable report with timing, fixes, rules, warnings, and snapshots
Features:
- Zero overhead when diagnostics are not enabled
- Configurable snapshot capture with truncation limits
- Per-fix and per-rule timing measurements
- Warning emission from DataFix implementations
Presets:
DiagnosticOptions.defaults()— Full diagnostics with snapshots and rule detailsDiagnosticOptions.minimal()— Timing only, minimal overhead
⚡ High-Performance APIs
BatchTransform:
Rules.batch(ops, batch -> batch
.rename("oldName", "newName")
.remove("deprecated")
.set("version", d -> d.createInt(2))
.transform("count", d -> d.createInt(d.asInt(0) + 1))
.addIfMissing("created", d -> d.createLong(System.currentTimeMillis()))
)Single-Pass Conditionals:
Rules.conditionalTransform(ops,
d -> d.get("type").asString("").equals("legacy"),
d -> d.set("migrated", d.createBoolean(true))
)🚀 Performance Optimizations
Internal optimizations with no API changes:
- Path parsing uses character-based parsing with memoization cache
DataFixRegistry.getFixes()pre-allocates result listDataFixerImplmoves validation to registration time- Reduced allocations in hot paths
📝 Changelog
New in 0.2.0
- Testkit module with fluent builders, assertions, and test harnesses
- Extended rewrite rules for batch, grouping, path, and conditional operations
- Migration diagnostics system with timing and snapshots
- High-performance batch transformations
- Single-pass conditional APIs
- Performance optimizations (memoization, pre-allocation)
- Comprehensive documentation updates
Full Changelog: v0.1.0...v0.2.0
🗺️ Roadmap (next)
-
v0.3.0
- CLI module — Migrate files and print/export a migration report (batch-friendly)
- Schema tooling — Runtime schema validation + diff utilities between versions
-
v0.4.0
- Spring Boot integration — Auto-configuration for DataFixer in Spring apps
- Extra ops modules — Optional YAML/TOML support (format adapters)
- Debug utilities — Pretty printers / tree diff for Dynamic structures (dev-facing)
-
v0.5.0 (API freeze candidate)
- API stabilization pass — Naming/packaging cleanup + deprecations completed
- Compatibility checks in CI — Binary/source compatibility guardrails for public API
- Hardened error model — Consistent exception types + structured error details
- Release readiness — Final review of docs/examples against frozen API
📜 License
MIT — see LICENSE.
🚀 Aether Datafixers v0.1.0 — Initial Release
Aether Datafixers is a lightweight data migration framework for the JVM.
It enables forward patching of serialized data through schema definitions and versioned fixers —
inspired by Minecraft's DataFixer Upper (DFU), with a focus on simplicity, clarity, and ease of use.
🎯 Highlights in v0.1.0
- ✅ Schema-Based Versioning
- Define data types per version with
SchemaandTypeRegistry.
- Define data types per version with
- ✅ Forward Patching
- Apply
DataFixinstances sequentially to migrate data across versions.
- Apply
- ✅ Format-Agnostic
- Work with any serialization format via
Dynamic<T>andDynamicOps<T>.
- Work with any serialization format via
- ✅ Codec System
- Bidirectional transformation between typed Java objects and dynamic representations.
- ✅ Optics
- Composable, type-safe accessors (
Lens,Prism,Iso,Traversal) for nested data structures.
- Composable, type-safe accessors (
- ✅ Type Safety
- Strong typing with
TypeReferenceidentifiers for data routing.
- Strong typing with
📦 Installation
Tip
All Aether artifacts are available on Maven Central — no extra repository required.
Maven
<dependency>
<groupId>de.splatgames.aether</groupId>
<artifactId>aether-datafixers-core</artifactId>
<version>0.1.0</version>
</dependency>Using the BOM
<dependencyManagement>
<dependencies>
<dependency>
<groupId>de.splatgames.aether</groupId>
<artifactId>aether-datafixers-bom</artifactId>
<version>0.1.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<!-- No version needed -->
<dependency>
<groupId>de.splatgames.aether</groupId>
<artifactId>aether-datafixers-core</artifactId>
</dependency>
</dependencies>Gradle (Groovy)
dependencies {
implementation 'de.splatgames.aether:aether-datafixers-core:0.1.0'
// Or with BOM:
implementation platform('de.splatgames.aether:aether-datafixers-bom:0.1.0')
implementation 'de.splatgames.aether:aether-datafixers-core'
}Gradle (Kotlin)
dependencies {
implementation("de.splatgames.aether:aether-datafixers-core:0.1.0")
// Or with BOM:
implementation(platform("de.splatgames.aether:aether-datafixers-bom:0.1.0"))
implementation("de.splatgames.aether:aether-datafixers-core")
}🧰 Usage
1) Define a Bootstrap
public class MyBootstrap implements DataFixerBootstrap {
@Override
public void registerSchemas(SchemaRegistry schemas) {
// Register schema for each version
}
@Override
public void registerFixes(FixRegistrar fixes) {
// Register DataFix instances for type migrations
}
}2) Create the DataFixer
AetherDataFixer fixer = new DataFixerRuntimeFactory()
.create(currentVersion, new MyBootstrap());3) Apply Migrations
Dynamic<?> updated = fixer.update(
TypeReference.of("player"),
inputDynamic,
fromVersion,
toVersion
);📝 Changelog
New in 0.1.0
- 🎉 Initial release with complete data migration pipeline:
- Schema-based versioning with
TypeRegistry DataFixforward patching systemDynamic<T>/DynamicOps<T>format abstraction- Codec infrastructure for bidirectional serialization
- Optics system (
Lens,Prism,Iso,Affine,Traversal) SchemaDataFixbase class for schema-aware migrations- Runnable examples module demonstrating real-world usage
- Schema-based versioning with
🗺️ Roadmap (next)
-
0.2.x
- Additional codec implementations
- Extended type rewrite rules
- Performance optimizations
-
1.0.x
- Stable API surface
- Comprehensive documentation
- Production-ready release
📜 License
MIT — see LICENSE.