-
Notifications
You must be signed in to change notification settings - Fork 0
Constraints and Metadata
Constraint annotations state the rules a field's value must satisfy. Lite Config enforces them on every load and update and exposes them through config metadata.
@Config(name = "mymod")
public final class MyModConfig {
@Entry(comment = "Scale of the HUD overlay.")
@Range(min = 1, max = 8)
public int hudScale = 2;
@Pattern("[a-z0-9_]+")
@Length(max = 16)
public String profileName = "default";
@Length(min = 1, max = 4)
public List<String> enabledFeatures = new ArrayList<>(List.of("hud"));
public RenderMode mode = RenderMode.BALANCED;
}@Range(min, max) bounds a numeric field. Both attributes are optional, so
@Range(min = 0) leaves the upper end open. The bounds are inclusive.
@Pattern(regex) requires a string field to match the expression in full.
@Length(min, max) bounds the size of a string, collection, map, or array.
An enum field needs no annotation — its constants already are the set of values it accepts.
A constraint must match the field type: @Range supports numeric fields, @Pattern supports
strings, and @Length supports strings, collections, maps, and arrays. A mismatched annotation, a
range with a NaN bound, a min above its max, or an expression that does not compile is a
mistake in the config class rather than in the file. It is reported with INVALID_CONSTRAINT when
the holder is built.
A violated rule behaves exactly like one raised from validate: the update is rejected as a whole
and the reason comes back in the result.
UpdateResult result = holder.update(config -> config.hudScale = 12);
result.accepted(); // false
result.violations().getFirst().id(); // "range.hudScale"Violation ids follow the rule that produced them — range., pattern., length., or value. for
an enum the file names incorrectly — followed by the path of the field in the file. A field inside a
nested object uses its full path, so section.max_depth reads the same way in the violation as it
does in the file.
Constraints run before validate, so a hook of your own only sees candidates that already satisfy
the declared rules. NaN is rejected whenever @Range is present, including an otherwise
open-ended range.
Config files render only comments explicitly declared with @Config(comment = ...) and
@Entry(comment = ...). Defaults, constraints, restart requirements, and migration versions remain
available through metadata but do not generate file comments.
ConfigHolder#metadata() returns everything the annotations say, which is what a settings screen, a
command, or a documentation generator needs.
ConfigMetadata metadata = holder.metadata();
ConfigProperty hudScale = metadata.property("hudScale").orElseThrow();
hudScale.defaultValue(); // 2
hudScale.constraints().max(); // OptionalDouble[8.0]
hudScale.translationKey(); // Optional.empty()
metadata.flatten().forEach(property ->
System.out.println(property.path() + " -> " + property.type().getSimpleName()));property(path) takes the same dotted path the file uses. flatten() walks the whole tree,
nested objects included; properties() stays at the top level and lets you descend through
children() yourself.
Metadata describes the config; it never touches the live state. Collection and map defaults are
immutable snapshots, and array defaults are copied on access. A mutable value handled by a custom
codec should still be treated as read-only and copied before editing. Change live values through
ConfigHolder#update or updateAndSave.
@Entry(translationKey = ...) records a field label for settings screens and other integrations.
Lite Config exposes the key through metadata but does not resolve it. See Field Entries for an
example.