Code generation cache
View MarkdownStatus: Stable Package:
dev.vertique.codegen.cacheArtifact:vertique-codegen-cacheDepends on:vertique-cache-aop,vertique-codegen-coreAPI reference: javadoc.io
vertique-codegen-cache is the build-time module boundary for cache annotation validation. It
remains separate from the provider-neutral runtime and from storage providers. It is an
annotation-processor artifact, not a runtime dependency.
When To Use It
Section titled “When To Use It”Use this artifact in the compile-time processor path of applications that use cache annotations.
Runtime applications should declare vertique-cache-aop and a concrete provider according to
their composition.
Core Concepts
Section titled “Core Concepts”The registered CacheAnnotationProcessor validates @Cacheable and @CacheEvict declarations,
rejects co-located cacheable and eviction annotations, and returns all proxy and metadata generation
to the generic AOP processor. Provider composition
is explicit: the application includes a concrete provider module, which includes the cache core
and cache AOP bindings. The generic AOP processor emits the application-owned subclass proxy and
reflection-free MethodMetadata; generated types belong to the consuming application
compilation and are not supplied by a runtime provider module.
Validation boundary
Section titled “Validation boundary”The processor validates cache declarations at compilation. A cacheable or eviction method
must be declared on a public, non-final class with exactly one constructor annotated with
jakarta.inject.Inject or javax.inject.Inject. The annotated method must be an instance
method that can be overridden; final, private, static, abstract, and non-proxyable method
shapes produce diagnostics. @Cacheable methods must return a value, and raw, wildcard, or
type-variable Future results are rejected.
Keys are ordered selector-path arrays: key = {"tenantId", "user.email"}. Each path is a
positional ("0") or parameter-name ("user") root plus at most seven dot-separated
property segments (eight segments including the root). There is no template or literal
text; the runtime alone composes and frames the canonical key. An explicitly empty
key = {} declares a constant, value-independent operation key. Each property must
resolve to a public, zero-argument instance accessor: a bare segment resolves only to a
record component, while a bean property requires a JavaBean getX()/isX() accessor.
The terminal must be one of the
processor’s supported scalar shapes:
| Shape | Accepted types |
|---|---|
| Text and primitives | String, char/Character, boolean/Boolean, and numeric primitives or wrappers |
| Numeric values | BigInteger, BigDecimal |
| Other scalar values | UUID, enum types, and java.time.temporal.TemporalAccessor types |
Blank paths, invalid identifiers, unresolved parameters or accessors, excessive property depth, object/container terminals, and unsupported return shapes produce compile-time diagnostics. The processor does not perform a separate ambiguity check; a path must resolve through the ordinary parameter and accessor lookup rules.
For @CacheEvict, proxyability is always validated, and a declaration must specify
exactly one of clear = true or an explicit key attribute — a declaration with
neither, or with both a key and clear = true, is a compile-time diagnostic. An
explicit nonempty key is path-validated; an explicit empty key is the constant-entry
exact eviction; a clear operation has no selector to validate.
For a JAX-RS @GET method, @Cacheable accepts an entity or Future<entity> result. HTTP
response wrappers, transport response types, buffers, routing contexts, streams, publishers,
and Multi results are rejected. The processor emits no selector toString() fallback.
The generic AOP processor emits reflection-free method metadata; the cache annotation adapter
uses it to invoke the validated record or bean accessor and fails open when a null or invalid
value cannot produce a key. The configured CacheConfig.maxKeyBytes limit applies to the complete
canonical UTF-8 key; its default is 1,024 bytes.
Inherited annotations are not promoted to a different concrete bean by this processor; the validated method belongs to its declaring class. Self-invocation is not diagnosed here: interception occurs only when a call enters the generated AOP override, so direct construction and calls that bypass the proxy are not intercepted.
@Cacheable / @CacheEvict on an interface method
Section titled “@Cacheable / @CacheEvict on an interface method”@Cacheable or @CacheEvict on an interface method is a compile error. This processor enforces
a cache-owned placement rule and reports “cache annotations must be declared on concrete class
methods”. Move the annotation to the implementing class’s method.
This differs deliberately from the generic AOP processor (vertique-codegen-aop), which now weaves
aspect triggers placed on interface methods. Cache annotations still require concrete class methods
and reject the misplacement at build time.
The generic AOP processor must be present on the application’s annotation-processor path alongside this artifact for the validated annotations to produce proxies and metadata.
Key Classes
Section titled “Key Classes”CacheAnnotationProcessor
Section titled “CacheAnnotationProcessor”AbstractProcessor registered via META-INF/services/javax.annotation.processing.Processor.
@SupportedAnnotationTypes({ "dev.vertique.cache.aop.Cacheable", "dev.vertique.cache.aop.CacheEvict"})@SupportedSourceVersion(SourceVersion.RELEASE_21)Validates every @Cacheable / @CacheEvict method as described under Validation boundary.
process() always returns false, so other processors still see the annotations, and the
processor generates no sources.
Verification
Section titled “Verification”A clean reactor build regenerates AOP output from the consuming application sources; stale generated output is not a runtime provider dependency. Run the processor proof with:
./mvnw -ntp -pl vertique-codegen/vertique-codegen-cache -am verifyThe package-level clean build also verifies dependency/BOM parity and packaged module-documentation parity:
./mvnw -ntp clean verifyDependencies
Section titled “Dependencies”| Artifact | Purpose |
|---|---|
vertique-cache-aop |
Cache annotations and runtime AOP adapters |
vertique-codegen-core |
Shared annotation-processor utilities |