Skip to content

Releases: aether-framework/aether-datafixers

🚀 Aether Datafixers v0.4.0 — Spring Boot Integration & Multi-Format DynamicOps

10 Jan 12:52

Choose a tag to compare

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-starter module with auto-configuration, fluent MigrationService API, 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

08 Jan 19:43

Choose a tag to compare

Command-line interface for batch migrations, schema analysis tools, and naming convention validation.


🎯 Highlights in v0.3.0

  • CLI Module — New aether-datafixers-cli module for migrating and validating data files from the command line with batch processing and reports.
  • Schema Tools Module — New aether-datafixers-schema-tools module 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 .bak backup
  • 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 types

Migration 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

07 Jan 09:17

Choose a tag to compare

Extended rules, testkit module, migration diagnostics, and high-performance APIs.


🎯 Highlights in v0.2.0

  • Testkit Module — New aether-datafixers-testkit module 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 Jackson
  • AetherAssertions — Custom AssertJ assertions for Dynamic, DataResult, Typed
  • DataFixTester — Test harness for individual DataFix implementations
  • MigrationTester — Test harness for complete migration chains
  • SchemaTester — Test harness for Schema validation
  • QuickFix — Factory methods for common fix patterns
  • MockSchemas — Factory for mock Schema instances
  • RecordingContext / 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 capture
  • DiagnosticContext — Context interface for diagnostic migrations
  • MigrationReport — 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 details
  • DiagnosticOptions.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 list
  • DataFixerImpl moves 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

22 Dec 16:25

Choose a tag to compare

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 Schema and TypeRegistry.
  • Forward Patching
    • Apply DataFix instances sequentially to migrate data across versions.
  • Format-Agnostic
    • Work with any serialization format via Dynamic<T> and DynamicOps<T>.
  • Codec System
    • Bidirectional transformation between typed Java objects and dynamic representations.
  • Optics
    • Composable, type-safe accessors (Lens, Prism, Iso, Traversal) for nested data structures.
  • Type Safety
    • Strong typing with TypeReference identifiers for data routing.

📦 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
    • DataFix forward patching system
    • Dynamic<T> / DynamicOps<T> format abstraction
    • Codec infrastructure for bidirectional serialization
    • Optics system (Lens, Prism, Iso, Affine, Traversal)
    • SchemaDataFix base class for schema-aware migrations
    • Runnable examples module demonstrating real-world usage

🗺️ 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.