All notable changes to this project will be documented in this file.
This project adheres to Semantic Versioning.
This release marks the API freeze for Aether Datafixers. The public API is now stable and no breaking changes are expected before v1.0.0.
The SchemaValidator.validateFixCoverage() method now performs actual coverage analysis using MigrationAnalyzer:
- Full MigrationAnalyzer integration — Detects missing DataFixes for schema changes
- Automatic version range detection — Scans the entire schema registry to determine version bounds
- Field-level coverage gaps — Reports issues for added, removed, or modified fields without fixes
- Detailed context — Issues include type, field name, version range, and gap reason
Usage:
ValidationResult result = SchemaValidator.forBootstrap(bootstrap)
.validateFixCoverage()
.validate();
for (ValidationIssue issue : result.warnings()) {
System.out.println(issue.message());
// "Missing DataFix for type 'player' field 'health': FIELD_ADDED"
}The Spring Boot MigrationService now fully supports custom DynamicOps for format conversion:
- Format conversion during migration — Convert input data to specified format before migration
- Seamless API integration — Works with the existing fluent builder API
- All formats supported — Gson, Jackson JSON, YAML (both), TOML, and XML
Usage:
// Convert Gson data to Jackson YAML format during migration
MigrationResult result = migrationService
.migrate(gsonData)
.from(100)
.to(200)
.withOps(JacksonYamlOps.INSTANCE)
.execute();
// Result data is now in Jackson YAML format
Dynamic<JsonNode> yamlResult = (Dynamic<JsonNode>) result.getData();New module with comprehensive end-to-end and integration tests:
- Cross-format migration tests — Verify migrations work identically across all DynamicOps implementations
- Error recovery tests — Test graceful handling of malformed data and fix failures
- Field transformation E2E tests — Validate rename, add, remove, and group operations
Running:
mvn verify -PitExtended the CLI with four new built-in format handlers:
YAML Support:
YamlSnakeYamlFormatHandler— Format IDyaml-snakeyaml, uses SnakeYAML with native Java typesYamlJacksonFormatHandler— Format IDyaml-jackson, uses Jackson YAML with JsonNode
TOML Support:
TomlJacksonFormatHandler— Format IDtoml-jackson, uses Jackson TOML with JsonNode
XML Support:
XmlJacksonFormatHandler— Format IDxml-jackson, uses Jackson XML with JsonNode
Usage Examples:
# Migrate YAML files
aether-cli migrate --format yaml-snakeyaml --to 200 --type config input.yaml
# Migrate TOML configuration
aether-cli migrate --format toml-jackson --to 200 --type config config.toml
# Migrate XML data
aether-cli migrate --format xml-jackson --to 200 --type player data.xmlNew CLI Dependencies:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-toml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>Added new factory methods to TestData for all supported formats:
| Method | Format | Data Type | DynamicOps Used |
|---|---|---|---|
jacksonJson() |
JSON | JsonNode |
JacksonJsonOps |
snakeYaml() |
YAML | Object |
SnakeYamlOps |
jacksonYaml() |
YAML | JsonNode |
JacksonYamlOps |
jacksonToml() |
TOML | JsonNode |
JacksonTomlOps |
jacksonXml() |
XML | JsonNode |
JacksonXmlOps |
Usage:
// YAML test data with SnakeYAML
Dynamic<Object> yamlData = TestData.snakeYaml().object()
.put("name", "test")
.put("value", 42)
.build();
// TOML test data
Dynamic<JsonNode> tomlData = TestData.jacksonToml().object()
.put("key", "value")
.build();
// XML test data
Dynamic<JsonNode> xmlData = TestData.jacksonXml().object()
.put("element", "content")
.build();New Testkit Dependencies:
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-toml</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
</dependency>Added test classes for all new format handlers with full coverage:
YamlSnakeYamlFormatHandlerTest— 21 tests for SnakeYAML handlerYamlJacksonFormatHandlerTest— 20 tests for Jackson YAML handlerTomlJacksonFormatHandlerTest— 19 tests for Jackson TOML handlerXmlJacksonFormatHandlerTest— 20 tests for Jackson XML handler
Tests cover parsing, serialization, error handling, and round-trip consistency.
The TestData.jackson() method is deprecated and will be removed in version 1.0.0.
Reason: With the addition of multiple Jackson-based format handlers (JSON, YAML, TOML, XML), explicit format naming is required for clarity.
Migration:
// Before (deprecated)
Dynamic<JsonNode> data = TestData.jackson().object().build();
// After
Dynamic<JsonNode> data = TestData.jacksonJson().object().build();- Updated Format Handlers with all new built-in handlers
- Updated Test Data Builders with new factory methods and deprecation notice
- Added version 0.5.0 section to Documentation Changelog
The codec module has been restructured to use a format-first package organization. This is a breaking change that requires updating import statements.
Old Package Structure:
de.splatgames.aether.datafixers.codec.gson.GsonOps
de.splatgames.aether.datafixers.codec.jackson.JacksonOps
New Package Structure:
de.splatgames.aether.datafixers.codec.json.gson.GsonOps
de.splatgames.aether.datafixers.codec.json.jackson.JacksonJsonOps
de.splatgames.aether.datafixers.codec.yaml.snakeyaml.SnakeYamlOps
de.splatgames.aether.datafixers.codec.yaml.jackson.JacksonYamlOps
de.splatgames.aether.datafixers.codec.toml.jackson.JacksonTomlOps
de.splatgames.aether.datafixers.codec.xml.jackson.JacksonXmlOps
Migration Steps:
- Update imports from
codec.gson.GsonOpstocodec.json.gson.GsonOps - Update imports from
codec.jackson.JacksonOpstocodec.json.jackson.JacksonJsonOps - Rename
JacksonOpsreferences toJacksonJsonOps
New DynamicOps implementations for YAML, TOML, and XML formats:
YAML Support:
SnakeYamlOps— Uses native Java types (Map,List, primitives) via SnakeYAML 2.xJacksonYamlOps— UsesJsonNodevia Jackson YAML dataformat module
TOML Support:
JacksonTomlOps— UsesJsonNodevia Jackson TOML dataformat module- Note: TOML requires top-level tables and doesn't support null values
XML Support:
JacksonXmlOps— UsesJsonNodevia Jackson XML dataformat module- Note: XML requires a root element and has different structural semantics
New Dependencies (all optional):
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>
<version>2.2</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-toml</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<optional>true</optional>
</dependency>New module providing seamless Spring Boot integration with auto-configuration, fluent migration API, and observability features.
Auto-Configuration (spring.autoconfigure):
AetherDataFixersAutoConfiguration— Main entry point coordinating all sub-configurationsDynamicOpsAutoConfiguration— Auto-configuresGsonOpsandJacksonOpsbeans based on classpathDataFixerAutoConfiguration— CreatesAetherDataFixerbeans fromDataFixerBootstrapdefinitionsMigrationServiceAutoConfiguration— Configures theMigrationServicewith metrics integrationActuatorAutoConfiguration— Configures health indicators, info contributors, and custom endpoints- Conditional activation via
aether.datafixers.enabledproperty (default:true) - Version resolution from properties, bootstrap
CURRENT_VERSIONconstant, or global default
Configuration Properties (spring.config):
AetherDataFixersProperties— Root configuration withaether.datafixers.*prefixDataFixerDomainProperties— Per-domain configuration (version, primary, description)DynamicOpsFormat— Enum for selecting default serialization format:GSON— JSON via Google GsonJACKSON— JSON via Jackson DatabindJACKSON_YAML— YAML via Jackson dataformatSNAKEYAML— YAML via SnakeYAML (native Java types)JACKSON_TOML— TOML via Jackson dataformatJACKSON_XML— XML via Jackson dataformat
ActuatorProperties— Control schema/fix detail exposure in actuator responsesMetricsProperties— Configure timing, counting, and domain tag name
Migration Service (spring.service):
MigrationService— High-level interface with fluent builder APIMigrationService.MigrationRequestBuilder— Builder for configuring migrationsDefaultMigrationService— Thread-safe implementation with metrics integrationMigrationResult— Immutable result object with success/failure, data, versions, duration, error- Fluent API:
.migrate(data).from(version).to(version).execute() - Domain selection:
.usingDomain("game")for multi-domain setups - Latest version resolution:
.toLatest()resolves at execution time - Async execution:
.executeAsync()returnsCompletableFuture<MigrationResult> - Custom DynamicOps:
.withOps(ops)for custom serialization
Multi-Domain Support (spring.autoconfigure):
DataFixerRegistry— Thread-safe registry for managing multiple DataFixer instances- Support for
@Qualifierannotated bootstrap beans createQualifiedFixer()factory method for domain-specific DataFixer creation- Domain availability checking via
hasDomain()andgetAvailableDomains() - Default domain ("default") for single-bootstrap setups
Actuator Integration (spring.actuator):
DataFixerHealthIndicator— Reports UP/DOWN/UNKNOWN based on DataFixer operational statusDataFixerInfoContributor— Addsaether-datafixerssection to/actuator/infoDataFixerEndpoint— Custom endpoint at/actuator/datafixerswith domain details- Per-domain health status and version information
- Domain-specific endpoint:
/actuator/datafixers/{domain} - Fail-fast on first domain error with detailed error message
Micrometer Metrics (spring.metrics):
MigrationMetrics— Records migration metrics using Micrometeraether.datafixers.migrations.success— Counter for successful migrations (tagged by domain)aether.datafixers.migrations.failure— Counter for failed migrations (tagged by domain, error_type)aether.datafixers.migrations.duration— Timer for migration execution timeaether.datafixers.migrations.version.span— Distribution summary of version spans- Automatic metric recording in
DefaultMigrationService - Thread-safe meter caching per domain
- Added new
docs/codec/section with comprehensive format documentation - Codec Overview — Format comparison, package structure, dependency guide
- JSON Support — GsonOps and JacksonJsonOps usage, examples, comparison
- YAML Support — SnakeYamlOps and JacksonYamlOps usage, examples, comparison
- TOML Support — JacksonTomlOps usage, configuration file examples
- XML Support — JacksonXmlOps usage, XML-to-JsonNode mapping
- Updated Dynamic System with all DynamicOps implementations table
- Updated Codec System with links to format-specific docs
- Updated How-To Index with Format Integration section
- Updated Custom DynamicOps Tutorial with built-in implementations reference
- Added comprehensive Spring Boot Integration documentation
- Quick Start Guide with complete code examples
- Configuration Reference for all
aether.datafixers.*properties - MigrationService API documentation with sync/async patterns
- Multi-Domain Setup guide with
@Qualifierexamples - Actuator Integration guide with security recommendations
- Metrics Integration guide with PromQL queries, Grafana dashboard, and alerting rules
- Updated main documentation with Spring Boot module links
New module for schema analysis, validation, and migration coverage checking.
Schema Diffing (schematools.diff):
SchemaDiffer— Fluent API for comparing two schemasSchemaDiff— Immutable result with added/removed/common typesTypeDiff— Field-level changes for types present in both schemasFieldDiff— Individual field change (ADDED, REMOVED, MODIFIED, UNCHANGED)DiffKind— Enumeration of change types- Optional field-level diffing via
includeFieldLevel(true) - Type filtering via
ignoreTypes(...)
Migration Analysis (schematools.analysis):
MigrationAnalyzer— Fluent API for analyzing migration pathsMigrationPath— Complete migration sequence with all stepsMigrationStep— Single version transition with optional DataFix and SchemaDiffFixCoverage— Analysis result showing fix coverage for schema changesCoverageGap— Represents a schema change without corresponding DataFix- Coverage gap reasons: TYPE_ADDED, TYPE_REMOVED, TYPE_MODIFIED, FIELD_ADDED, FIELD_REMOVED, FIELD_TYPE_CHANGED
- Orphan fix detection (fixes without schema changes)
Schema Validation (schematools.validation):
SchemaValidator— Fluent API for validating schemasValidationResult— Immutable collection of validation issuesValidationIssue— Single issue with severity, code, message, location, contextIssueSeverity— ERROR, WARNING, INFO levelsStructureValidator— Validates schema structure (cycles, version ordering, parent chains)ConventionChecker— Validates naming conventions for types, fields, classesConventionRules— Configurable naming rules (STRICT, RELAXED, NONE, or custom)- Schema class prefix/suffix validation (e.g., "Schema" prefix for Schema100, Schema200)
- Fix class prefix/suffix validation (e.g., "Fix" suffix for PlayerNameFix)
- Predefined patterns for snake_case, camelCase
- Custom validators via
customTypeValidator()andcustomFieldValidator()
Type Introspection (schematools.introspection):
TypeIntrospector— Utility for analyzing type structuresTypeStructure— Normalized, comparable representation of a TypeFieldInfo— Field metadata (name, path, optionality, type)TypeKind— Classification (PRIMITIVE, LIST, OPTIONAL, PRODUCT, SUM, FIELD, etc.)- Recursive field extraction with hierarchical paths
- Structural equality comparison
New command-line interface for data migration without writing Java code.
Commands:
migrate— Migrate data files from one schema version to anothervalidate— Check if files need migration without modifying theminfo— Display version info, available formats, and bootstrap details
Core 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
- Fail-fast or continue-on-error modes
- CI/CD friendly exit codes (0=success, 1=error, 2=migration needed)
Format Handler System:
FormatHandler<T>— SPI for pluggable serialization formatsFormatRegistry— ServiceLoader-based handler discoveryjson-gson— JSON format using Google Gson (default)json-jackson— JSON format using Jackson Databind
Utilities:
BootstrapLoader— Reflective loading of DataFixerBootstrap implementationsVersionExtractor— Extract version from nested JSON paths (dot notation)ReportFormatter— Text and JSON migration report formattingTextReportFormatter— Human-readable single-line reportsJsonReportFormatter— Machine-readable JSON reports
Exceptions:
BootstrapLoadException— Bootstrap class loading failuresFormatParseException— Input parsing failures
- Added comprehensive Schema Tools documentation (diffing, analysis, validation, introspection)
- Added CLI module documentation (commands, format handlers, examples)
- Updated glossary with Schema Tools terminology
- Updated installation guide with new modules
- TestData — Fluent builders for creating test data (
TestData.gson().object()...) - AetherAssertions — Custom AssertJ assertions for
Dynamic,DataResult,Typed - DataFixTester — Test harness for isolated DataFix testing with fluent API
- MigrationTester — Test harness for full migration chain testing
- SchemaTester — Test harness for schema validation
- QuickFix — Factory methods for common fix patterns (rename, add, remove, transform)
- MockSchemas — Mock schema utilities for testing
- RecordingContext — Context that records warnings for test verification
- DiagnosticContext — Opt-in diagnostic context for capturing migration reports
- DiagnosticOptions — Configurable options (snapshots, rule details, pretty print)
- MigrationReport — Structured report with timing, applied fixes, and touched types
- FixExecution — Per-fix execution details with before/after snapshots
- RuleApplication — Per-rule application details
Rules.renameFields(ops, map)— Batch rename multiple fieldsRules.removeFields(ops, fields...)— Batch remove multiple fieldsRules.groupFields(ops, target, fields...)— Group flat fields into nested objectRules.flattenField(ops, field)— Flatten nested object to root levelRules.moveField(ops, source, target)— Move field between pathsRules.copyField(ops, source, target)— Copy field to new locationRules.transformFieldAt(ops, path, fn)— Transform at nested pathRules.renameFieldAt(ops, path, newName)— Rename at nested pathRules.removeFieldAt(ops, path)— Remove at nested pathRules.addFieldAt(ops, path, value)— Add at nested pathRules.ifFieldExists(ops, field, rule)— Conditional on field existenceRules.ifFieldMissing(ops, field, rule)— Conditional on field absenceRules.ifFieldEquals(ops, field, value, rule)— Conditional on field value
- BatchTransform — Builder for batching multiple field operations
Rules.batch(ops, builder)— Apply multiple operations in single encode/decode cycleRules.conditionalTransform(ops, predicate, transform)— Single-pass conditional transformRules.ifFieldExists(ops, field, transform)— Single-pass version (Function overload)Rules.ifFieldMissing(ops, field, transform)— Single-pass version (Function overload)Rules.ifFieldEquals(ops, field, value, transform)— Single-pass version (Function overload)
- Path parsing now uses character-based parsing instead of regex with memoization cache
DataFixRegistry.getFixes()pre-allocates result list and avoids second copyDataFixerImplremoves redundant validation in hot path (moved to registration time)- Fix version ordering validated once at registration instead of per-application
- Added comprehensive how-to guides for all extended rules
- Added migration diagnostics usage guide
- Updated quick reference with new APIs (including Testkit module)
- First stable release of the project.