Skip to content

Architecture Overview

Petrus Pradella edited this page Jun 28, 2026 · 6 revisions

Architecture Overview

EveryConfig is a thin set of layers over one canonical Jackson tree.

        text (yaml / json / toml / jsonc)
                 │   ▲
       readTree  │   │  writeWithComments / writeTreePlain
                 ▼   │
   ┌─────────────────────────────┐     ┌──────────────────────────┐
   │  Codec (codec.jackson.*)     │     │  CommentTree (overlay)    │
   │  text ⇄ ObjectNode + mapper  │     │  block/side/header/footer │
   └─────────────────────────────┘     └──────────────────────────┘
                 │   ▲                              ▲
                 ▼   │                              │
   ┌──────────────────────────────────────────────────────────────┐
   │  Config — the canonical ObjectNode + dynamic path API          │
   │  (setValue / getValue / typed getters / getOrSetValueIfAbsent)  │
   └──────────────────────────────────────────────────────────────┘
                 │                                  │
        EntityBinder (derived, merges)        Backend / io (atomic file I/O)

The pieces

Layer Package Role
Config config, config.section The handle: the canonical ObjectNode, the dynamic path API, the comment API, and the file lifecycle.
Core model core.tree, core.coerce, core.comment, core Path (dotted-path utils), NodeCoercion (the single Java ⇄ Jackson seam), CommentTree + CommentType, KeyOrder.
Codec codec, codec.jackson The Codec SPI + CommentFidelity + registry + mapper profiles; the four format codecs.
I/O io Atomic write, .bak rescue, reload, poll watcher, async executor.
Binding binding, binding.schema, binding.merge, binding.introspect The typed view: EntityBinder, the schema model, smart-merge + @Id indexing, the Jackson annotation bridge.
Annotations annotation @Key, @Comment, @Section, @Id, @PostLoad (+ KeyTransformCase, CommentMode).

The 5 design decisions

These are the invariants every layer obeys.

  1. The tree is canonical. The dynamic API operates on the ObjectNode. Typed binding is a derived view; on conflict the tree wins (unknown file keys survive, FAIL_ON_UNKNOWN_PROPERTIES is off), and a binding save merges into the tree, never replaces it.
  2. Comments = seed / override. @Comment and getOrSetValueIfAbsent(path, def, comment) write comments in two explicit modes — rewrite-every-save (OVERRIDE) or write-once (SET_IF_ABSENT). See Default Values & Comments.
  3. Comment fidelity is a codec capability. Each codec declares LOSSLESS / LOSSY / NONE. JSON is NONE. See Codecs & Formats.
  4. Save = reconciliation. Load captures the (data tree, CommentTree, KeyOrder); the emitter reconciles per path and emits in file order, appending new keys.
  5. The emitter renders structure itself (keys, indent, sections, comment lines) and delegates only leaf-value serialization to the ObjectMapper — the mapper's output is never re-parsed, so a custom mapper can restyle a value but cannot break the layout. The Codec (text⇄tree⇄entity) is separate from the I/O layer (atomic file writes).

One shared mapper per codec

A Codec holds a single, thread-safe Jackson ObjectMapper, shared across every live Config of that format. There is no per-file engine, no pool, no ThreadLocal — a config's footprint is just its tree.

→ See also Project Layout · The Dynamic API · Entity Binding

Clone this wiki locally