Lossless Configuration
Configuration files are often edited by humans and generated by software. A useful library needs to preserve both sides: the value the application reads and the source detail that makes the file understandable.
Values Are Not the Whole File
A scalar value like 25565 can carry more information than the integer itself:
server:
# Public listener port.
port: 25565 # Restart required.
The application cares about the integer. The editor and writer care about the leading comment, inline comment, key position, scalar style, and surrounding structure.
Core Separates the Layers
PistonConfig keeps source layers distinct:
| Layer | Stored in |
|---|---|
| Application value | ConfigNode.kind(), child nodes, and rawValue() |
| Human comments | ConfigComment |
| Shared source details | ConfigNodeDecorations |
| Backend-specific details | ConfigNode.metadata() and format constants |
This avoids turning every backend into the lowest common denominator.
Backends Keep Their Strengths
YAML has tags, anchors, scalar styles, and multiple comment positions. Properties files have separators, escaped keys, repeated keys, and layout details. TOML has tables. HOCON has origin information and rendering behavior. JSONC and JSON5 can carry comments where strict JSON cannot.
PistonConfig maps shared behavior into core fields and leaves format-specific behavior under metadata constants.
Merging Uses the Same Model
Default merging works on ConfigNode, not raw text. That lets an application merge generated defaults, static field definitions, or annotation defaults into a user’s current file while preserving user values and available source metadata.
Practical Rule
Use core fields when behavior should work across formats. Use backend metadata constants when code needs a detail that only one format can provide.