Static Proxies
Annotation-driven proxy classes generated during compilation. Zero reflection at runtime.
ProxyBuilder ships a set of annotation processors that generate proxy classes
during javac. The generated classes wrap your interface and delegate to a
real implementation, with cross-cutting behaviour baked in at compile time.
The five annotations
| Annotation | Generated class wraps the target with… |
|---|---|
@StaticLoggingProxy | Method-call logging via the project logger |
@StaticMetricsProxy | Dropwizard timings per method |
@StaticVirtualProxy | Lazy instance creation strategy |
@StaticObjectAdapter | Functional-interface adapter slots per method |
@DynamicObjectAdapterBuilder | Adapter builder with setOriginal / withXxx API |
You put the annotation on the interface that you want to proxy. The
processor generates a class named after the interface plus a suffix (for
example, ServiceStaticLoggingProxy). Your code instantiates the generated
class and tells it which implementation to delegate to.
Why generated, not reflective
- No reflection at runtime. The generated class calls the real
implementation through a direct method call. There is no
Method.invoke(...). - GraalVM native image friendly. No reflective entries to configure.
- Smaller startup cost. No proxy class is synthesised at the moment of
use; it exists on disk after
javac. - You can read it. The generated source goes into
target/generated-sources/annotations/(Maven default). Open it, read it, step through it.
Compile-time safety
The processors will fail your build for shapes they cannot safely proxy:
finalclasses annotated for static proxy generation.finalmethods on a target type.privatemethods on a target type.staticmethods (unless-Aproxybuilder.failOnStaticMethods=false).
See Processor safety rules for the full list and the reasoning.
Combining annotations
You can put more than one annotation on the same interface. Each processor generates its own class. You pick which generated class to use at the point of construction.
If you need to combine behaviour within a single generated class — for example logging and metrics on the same proxy — write your own processor. See Custom Processors.
In this section
- @StaticLoggingProxy
Generate a logging wrapper for an interface at compile time.
- @StaticMetricsProxy
Generate a Dropwizard-timed wrapper for an interface at compile time.
- @StaticVirtualProxy
Generate a lazy-creation wrapper for an interface at compile time.
- @StaticObjectAdapter
Generate a static object adapter with one functional-interface slot per method.
- @DynamicObjectAdapterBuilder
Generate a builder for an object adapter with one withXxx() slot per method.