Repository navigation
Generalize annotation-processor machinery into a reusable processing framework #378
Copy link
Copy link
Open
Description
Subtask of #233 — generalizes BuilderProcessor's processing machinery into reusable form BEFORE the module move (#349), so the moved annotation-processing artifact carries a real processing framework, not just extracted parts.
Background
After the decoupling (#347/#348) the generic parts are reusable (mapping, model, options, SPI, logging) — but the process() loop skeleton is still bespoke: a new annotation processor would still hand-write element collection, the round loop, guarded per-element generation, and end-of-round handling.
Agreed design (IoC pipeline — framework owns the lifecycle, domain plugs hooks)
init: ctx = domain.createContext(env) // mutable carrier for per-element state
round:
processingOver → generate(domain.onProcessingOver(ctx)); report; done // last-round callback
elements = spec.collect(round) // selection spec
tasks = domain.plan(elements, ctx) // element + resolved config + output TypeName
registry.registerAll(tasks.outputs()) // former-generated recognition, up-front
for task in tasks (guarded, strict-mode error/warning reporting):
def = domain.analyse(task, ctx) // element → domain definition
targets = domain.map(def, ctx) // → List<GenerationTargetClassDto>
for t in targets: existsGuard → engine.generate(t, formatter.resolve(t.mode)) → write
Decisions:
- Element collection (
spec.collect) only finds — declarative spec: primary annotation types + optional meta-annotation marker (@SimpleBuilder.Template-style discovery) + opt-out annotation + allowedElementKinds + validator hook → deterministic, sorted set. Reading annotation values stays inplan(per-instance config, repeatable expansion, conflict detection are domain semantics). - Definition list flows by return value — collected at exactly two points: per-element
map()(a task may emit several classes) andonProcessingOver()for deferred outputs (Jackson-module style). Nothing accumulates inside the context; the context only carries per-element state. - Round-loop semantics:
processingOverfinalizer callback; the "generate in exactly one round" policy; the"*"+return falseclaiming policy; deterministic ordering. - Min JDK/source-version check parametrized — the consumer names the version.
- Target-exists / idempotent writing — always on (class-exists check before generating,
FilerExceptionhandling). ProcessingTarget— genericized to a per-element carrier (config + target package).SourceFormatterResolver— generic (already codegen-side enum).- Per-processor plugin registry stays domain — the
GeneratorRegistrygenerators are builder-specific; ServiceLoader mechanics are too thin to abstract now. - Engine selection —
ClassCodeGeneratorSPI exists; priority-based backend resolution is Backend priority: performance-optimized built-in, prefer Roaster when present #366. - Options —
OptionRegistry: declareCompilerOptions once → derivegetSupportedOptions()+ typed reads (kills today's hand-duplication).
New generic machinery (created in neutral packages inside processor, moved by #349 into annotation-processing)
AbstractCodegenProcessor(driver) + domain hook contractAnnotatedElementSpec/ element collectorOptionRegistry- Genericized
ProcessingTarget, target-exists guard, planned-output registration
Acceptance
BuilderProcessorcollapses onto the framework (its remaining code = builder spec +BuilderDefinitionCreator+BuilderToGenerationTypeMapper+RoasterCodeGenerator+ Jackson finalizer).simple-buildersbehavior and generated output byte-identical.- A second processor can be written as spec + hooks + backend — no hand-rolled process loop.
Preparatory to #349/#368 (artifact annotation-processing in the codegen extraction).
Metadata
Metadata
Assignees
Labels
No labels
Activity
processing: claim annotations via claimsAnnotations derived from the …
analysis: share array-attribute reading and class-value resolution vi…
processing: declare supported types via supportedAnnotationTypes() me…
processing: drop redundant @SupportedAnnotationTypes — framework defa…