ProxyGenerator class
Proxy Generator
Generates runtime proxy subclasses for all classes annotated with JetLeaf stereotypes such as:
@Service@Component@Configuration@AutoConfiguration@Repository@Controller
The proxies produced by this generator form the foundation of JetLeaf’s AOP interception system, enabling runtime interception, tracing, and behavior modification on user-defined services.
Overview
The ProxyGenerator operates as a build_runner code generator that:
- Scans Dart libraries for eligible annotated classes.
- Verifies extendability (non-
final, non-private). - Collects all import dependencies (both direct and transitive) for correct type alias resolution.
- Emits a new class prefixed with
$$, e.g.:
@Service()
class UserService { ... }
// Auto-generated:
final class $$UserService with Interceptable implements UserService, ClassGettable<UserService> {
final UserService delegate;
$$UserService(this.delegate);
@override
Future<User> findUser(String id) async => when<User>(
() async => delegate.findUser(id),
'findUser',
MethodArguments(positionalArgs: [id]),
);
}
Each generated proxy class:
- Implements both the target class and
ClassGettable<T>. - Mixes in
Interceptableto delegate method calls throughMethodInterceptorDispatcher. - Forwards properties and methods to the delegate object.
- Wraps interceptable methods with
when()for interception.
Generation Workflow
-
Annotation Scan
- Filters classes with JetLeaf stereotype annotations.
- Ensures they are not
finalor from an external package.
-
Import and Alias Construction
- Captures the original source file’s imports.
- Adds imports for JetLeaf core libraries:
package:jetleaf_core/intercept.dartpackage:jetleaf_lang/lang.dart
- Generates URI aliases to avoid import name collisions.
-
Proxy Emission
- Emits proxy class definitions with:
- Correct import aliasing
- Generated headers
- Wrapped delegates
- Method overrides supporting interception
- Emits proxy class definitions with:
-
Method Generation
- Each method override uses:
this.when<T>(...)if return type is async/interceptable- Direct
delegate.method(...)otherwise
- Each method override uses:
-
Property Forwarding
- Forwards getters/setters and public fields directly to delegate.
Design Notes
1. Interceptable Return Types
The generator detects methods returning Future or FutureOr and wraps
them in when<T>(), allowing asynchronous interception chains.
Future<User> getUser(String id) async => when<User>(
() async => delegate.getUser(id),
'getUser',
MethodArguments(positionalArgs: [id]),
);
2. Aliased Imports
Every referenced type (return types, parameter types, supertypes) is imported via URI aliases to prevent symbol conflicts and to ensure generated proxies are always valid even across modular package boundaries.
import 'package:my_app/src/user_service.dart' as _i1;
import 'package:jetleaf_core/intercept.dart' as _i2;
3. Safety and Compatibility
- Skips
dart:internal URIs automatically (dart:_internal, etc.) - Skips final or external classes
- Emits proxies into
_jetleafor configured build target directory
Internal API
_hasStereotypeAnnotation
Detects if a class has any of the known JetLeaf stereotypes, including
meta-annotations (e.g., custom annotations that themselves are annotated
with @Service).
_generateProxyForClass
The core emission logic that:
- Writes imports
- Declares proxy fields and constructors
- Generates property accessors and method overrides
- Implements
toClass()fromClassGettable
_emitMethodOverride
Builds method overrides that wrap async methods in interceptable calls.
Handles operator forwarding, parameter reconstruction, and argument
serialization into MethodArguments.
Generated Output Example
final class $$OrderService with Interceptable implements OrderService, ClassGettable<OrderService> {
final OrderService delegate;
$$OrderService(this.delegate);
@override
Future<Order> findOrder(String id) async {
return this.when<Order>(
() async => delegate.findOrder(id),
'findOrder',
MethodArguments(positionalArgs: [id]),
);
}
@override
Class<OrderService> toClass() => Class<OrderService>(null, delegate.getClass().getPackage()?.getName());
}
Integration Points
| System | Role |
|---|---|
| Interceptable | Provides when() logic and dispatcher bridge |
| ClassGettable | Enables runtime type reflection support |
| ProxyCommandRunner | CLI entrypoint that triggers ProxyGenerator via build_runner |
| MethodInterceptorDispatcher | Executes registered interceptors per method |
Developer Notes
- Proxies are generated at compile-time via
build_runner. - Proxy generation should be run prior to hot reload or packaging.
- This generator does not modify the original source files.
Related
Interceptable— mixin for runtime interception- ProxyCommandRunner — CLI command invoking this generator
MethodInterceptorDispatcher— dispatcher managing intercept chainsClassGettable— runtime type metadata provider
Constructors
- ProxyGenerator()
- Proxy Generator
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
Methods
-
generate(
LibraryReader library, BuildStep buildStep) → FutureOr< String> - Generates Dart code for an input Dart library.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited