Skip to content

Project Layout

Petrus Pradella edited this page Aug 5, 2026 · 7 revisions

Project Layout

Two-module Gradle project; base package br.com.finalcraft.everyconfig. The folder name and the published artifact name differ on purpose: core/ ships as everyconfig-core, rules/ as everyconfig-rules.

EveryConfig/
├── build.gradle                     # the shared build: Java 25 toolchain, Jabel -> Java 8 floor, publishing
├── settings.gradle                  # include 'core', include 'rules'
├── gradle/libs.versions.toml        # version catalog (single source of truth for versions)
├── gradle.properties                # auto-download off; Gradle auto-detects local JDKs
├── CHANGELOG.md
│
├── core/                            # -> everyconfig-core
│   ├── build.gradle                 # Jackson deps + the java-test-fixtures harness (not published)
│   └── src/
│       ├── main/java/br/com/finalcraft/everyconfig/
│       │   ├── ECVersion.java           # version marker (mirrors the Gradle version)
│       │   ├── config/                  # Config (dynamic API + lifecycle + inMemory/changeCodec), LoadStatus,
│       │   │   │                        #   MigrationResult, ConfigIOException
│       │   │   └── section/             # ConfigSection (scoped path view)
│       │   ├── core/
│       │   │   ├── KeyOrder.java        # captured key order, consulted on save
│       │   │   ├── tree/                # DPath (dotted-path utilities; avoids java.nio.file.Path)
│       │   │   ├── coerce/              # NodeCoercion (the Java <-> Jackson seam), TypeFamily
│       │   │   └── comment/             # CommentTree, CommentType, CommentStyle (the comment overlay)
│       │   ├── codec/                   # Codec SPI, CommentFidelity, CommentAware, CodecRegistry,
│       │   │   │                        #   CodecException, ECMapperProfiles
│       │   │   └── jackson/             # JsonCodec, YamlCodec, TomlCodec, JsoncCodec, InMemoryCodec
│       │   ├── io/                      # BackStore, AtomicFileBackStore, FilePollWatcher, ConfigExecutors
│       │   ├── binding/                 # EntityBinder, BindOptions, BindException, LoadIssue, LoadIssueAware,
│       │   │   │                        #   ConfigContext, ConfigLifecycle
│       │   │   ├── schema/              # Schema, SchemaCache, ClosedSchema, BindingNames
│       │   │   ├── merge/               # SmartMerge, KeyIndexer, LifecycleInvoker, LifecycleGraphWalker
│       │   │   └── introspect/          # EveryConfigAnnotationIntrospector, EveryConfigModule, EnumNameSerializer
│       │   ├── rule/                    # the rule SEAM and not one rule: @ConfigRule, RuleHandler, RuleSelector,
│       │   │                            #   RuleEngine, RuleSite, RuleModel, RuleContext, RuleViolation,
│       │   │                            #   RulePolicy, @RuleReview, RuleBindDriver
│       │   ├── selfdescribe/            # the compact list-element SPI
│       │   └── annotation/              # @Key, @Comment, @Section, @KeyIndex, @PreLoad/@PostLoad/@PreSave/@PostSave,
│       │                                #   @EveryConfigCompactValue/@EveryConfigCompactCreator, KeyTransformCase
│       ├── testFixtures/java/.../testkit/   # CodecMatrixTest — the harness every cross-codec suite runs on
│       └── test/java/br/com/finalcraft/everyconfig/
│           ├── testdata/                # shared DTOs (Dtos, UltraComplexDTO)
│           ├── contract/                # AbstractConfigTest + 4 codec subclasses (+ contract/stress/)
│           └── codec/ binding/ io/ rule/ core/   # per-feature unit tests
│
└── rules/                           # -> everyconfig-rules (optional artifact)
    ├── build.gradle                 # api project(':core') + jakarta.validation-api
    └── src/
        ├── main/java/br/com/finalcraft/everyconfig/ruleset/
        │   ├── (root)               # @Explicit, @OneOf (+ OneOfSource), @Unique, their handlers, StandardRules
        │   ├── jakarta/             # JakartaRules + 22 handlers in presence/ size/ number/ text/ logic/ temporal/
        │   └── support/             # TargetTypes, Violations, Numbers, Sizes, Temporals, Regexes
        └── test/java/.../ruleset/
            ├── contract/            # AbstractRulesetTest + 4 codec subclasses
            └── data/                # the entities those suites bind

How the layers depend

  • config is the public handle; it uses core, codec and io, and offers binding as a derived view.
  • core is dependency-free model code (the tree, coercion, comments, key order).
  • codec knows the formats; codec.jackson holds the four concrete codecs.
  • io is file I/O only (no format knowledge).
  • binding is split by concern: the public API in binding, the schema model in binding.schema, the merge + @KeyIndex logic in binding.merge, and the Jackson bridge in binding.introspect.
  • rule is the seam the binder drives; it stays ONE package on purpose — RuleBindDriver builds RuleContext/RuleReviewContext through package-private constructors, so splitting it would mean making the bind's internals public.
  • ruleset (the other module) is the only place a concrete rule lives. It depends on rule, never the reverse: the core ships the mechanism and zero policy.

→ See also Architecture Overview and Semantic Rules

Clone this wiki locally