-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start
This walks from an empty file to a typed, documented, reloadable config.
import br.com.finalcraft.everyconfig.config.Config;
import br.com.finalcraft.everyconfig.codec.jackson.YamlCodec;
import java.nio.file.Paths;
Config cfg = Config.open(Paths.get("server.yml"), new YamlCodec());Or skip the codec — Config.open(String) (also File/Path) derives it from the file-name extension:
Config cfg = Config.open("server.yml"); // .yml -> YamlCodec, .toml -> TomlCodec, .json -> JsonCodec, ...This is fail-fast, not magic: a missing or unknown extension throws a
CodecException— it never guesses a format. Pass a codec explicitly (open(path, codec)) to override.
Config.open never throws on a bad file: an absent file starts empty, and a malformed one is backed up to
.bak and starts empty (see Lifecycle, Reload & Watching).
cfg.setValue("server.host", "localhost"); // auto-vivifies the "server" object
cfg.setValue("server.port", 25565);
String host = cfg.getString("server.host");
int port = cfg.getInt("server.port", 25565); // 2nd arg is the default if absentgetOrSetValueIfAbsent writes the default (and a comment) only if the path is absent, so it is safe to call
on every startup:
int maxPlayers = cfg.getOrSetValueIfAbsent("server.max-players", 20, "hard player cap");
boolean pvp = cfg.getOrSetValueIfAbsent("server.pvp", true, "allow player-vs-player");cfg.save(); // atomic write; comments and key order preservedThe resulting server.yml:
server:
host: localhost
port: 25565
# hard player cap
max-players: 20
# allow player-vs-player
pvp: trueclass ServerConfig {
public String host = "localhost";
public int port = 25565;
@Key(transformCase = KeyTransformCase.KEBAB_CASE)
public int maxPlayers = 20; // <-> key "max-players"
@PostLoad
void validate() {
if (port < 1 || port > 65535) throw new IllegalStateException("bad port");
}
}
ServerConfig sc = cfg.loadAs(ServerConfig.class, new YamlCodec()); // bind + run @PostLoad
sc.maxPlayers = 50;
cfg.mergeValue("", sc); // merge the POJO back into the tree (unknown keys survive; setValue would replace)
cfg.save();When the config was opened via Config.open(...), getValue binds a subtree without restating the codec —
the 2-arg form reuses the one the config carries:
ServerConfig sc = cfg.getValue("server", ServerConfig.class); // path-scoped loadAs
// "" or null -> the whole tree; an absent path -> the type's defaultsEverything above stays identical; only the codec (and extension) change:
Config cfg = Config.open(Paths.get("server.toml"), new TomlCodec());
// or new JsonCodec() / new JsoncCodec()Already opened over a file? You don't have to reopen to change formats:
cfg.save(new JsonCodec()); // one-shot: write THIS snapshot as JSON; the live codec is unchanged
cfg.changeCodec(new TomlCodec()); // switch the format for every later save() (the file path is untouched)Need a config with no file at all — a default template, a test fixture? Config.inMemory() gives the full
typed/POJO API (path API, getValue(path, type), @Key/@Section/@Comment) but has no back-store, so
save() throws:
Config template = Config.inMemory();
template.setValue("server.port", 25565);
ServerConfig sc = template.getValue("server", ServerConfig.class);A bare
new Config()is different: it has no codec, so it accepts only native values (scalars,Map,List,JsonNode) — a POJOsetValue/getValueneeds a codec, whichConfig.open(...)orConfig.inMemory()supply.
→ Next: Architecture Overview · The Dynamic API
EveryConfig · br.com.finalcraft:EveryConfig · One config API, every format, comments included · made by Petrus Pradella
Getting Started
Core Concepts
Typed Binding
Operations
Reference
Contributing