Config Advanced¶
This page covers format selection, migrations, adapters, and runtime-aware reload patterns.
Format Selection¶
If your @ConfigFile uses {ext}, MagicUtils can switch formats using:
<config>.formatnext to the config filemagicutils.formatin the config root directory-Dmagicutils.config.format=...MAGICUTILS_CONFIG_FORMAT
Supported values include json, jsonc, yml, yaml, and toml depending
on the installed format helpers.
If multiple candidate files exist, MagicUtils picks one and logs a warning.
Format Migration¶
When the selected format changes and an older format file exists, MagicUtils can migrate the data into the new target file. This is useful when moving from JSONC to YAML or TOML without forcing users to recreate their configs.
Schema Migrations¶
Register ordered ConfigMigration steps to evolve config schemas:
manager.registerMigrations(MyConfig.class,
new ConfigMigration() {
public String fromVersion() { return "0"; }
public String toVersion() { return "1"; }
public void migrate(Map<String, Object> root) {
root.put("enabled", true);
}
}
);
MagicUtils stores the current schema version in config-version.
Custom Adapters¶
Use ConfigAdapters.register(...) for custom value types:
ConfigAdapters.register(Duration.class, new ConfigValueAdapter<>() {
public Duration deserialize(Object value) { ... }
public Object serialize(Duration value) { ... }
});
Register adapters before the affected config class is first loaded.
Change Subscriptions¶
Use subscribeChanges(...) when you want an unsubscribe handle:
ListenerSubscription subscription = manager.subscribeChanges(MyConfig.class, (cfg, sections) -> {
// apply live update
});
Use onChange(...) when you only need fire-and-forget registration.
Runtime Resource Binding¶
MagicRuntime can rebuild managed resources on matching config changes:
MagicRuntimeConfigBinding<ServiceConfig, ReloadableClient> binding = runtime.bindConfig(
"service.client",
ServiceConfig.class,
config -> new ReloadableClient(config), // ReloadableClient implements AutoCloseable
"service"
);
Useful properties of this pattern:
- the latest resource is accessible via
binding.require() - the same resource is exposed through
runtime.requireNamedComponent("service.client", ReloadableClient.class) - replaced resources are closed automatically
binding.close()removes the named runtime component and stops listening for config changes
Validation And Constraints¶
@MinValue / @MaxValue¶
Clamp numeric config values to a safe range on load:
Out-of-range values are silently clamped. Set warn = false to suppress the
log message.
@SaveTo¶
Store a field in a separate file:
@ConfigSerializable¶
Enable a class for use inside config lists or maps:
@ListProcessor¶
Apply per-item validation when loading lists:
@ConfigValue("entries")
@ListProcessor(EntryProcessor.class)
private List<ServerEntry> entries = new ArrayList<>();
The processor implements ListItemProcessor<T> and returns ProcessResult.ok(),
ProcessResult.modified(value), or ProcessResult.replaceWithDefault().
Hot Reload¶
Mark reloadable sections and listen for updates:
Use section-aware reloads to avoid rebuilding unrelated services: