KeyGenerator — Strategy for Cache Key Generation
The KeyGenerator defines a strategy for producing unique, stable, and
deterministic keys that represent specific method invocations.
These keys serve as identifiers for cache lookups, insertions, and evictions.
🔍 Purpose
In any caching mechanism, a key determines how cached entries are stored
and retrieved. The role of KeyGenerator is to translate a method invocation
— including its target object, the reflective Method representation, and
the runtime MethodArgument values — into a single canonical key object.
This abstraction allows for flexible strategies:
- Default keying behavior for simple cases
- Domain-specific key formats (e.g., string concatenation, hashing, encoding)
- Integration with frameworks that require consistent key generation semantics
⚙️ Default Behavior
The base implementation provides a deterministic fallback strategy:
| Case | Condition | Resulting Key |
|---|---|---|
| 1 | No arguments | _SimpleKey.EMPTY |
| 2 | Single argument (named or positional) | The single argument itself |
| 3 | Multiple arguments | A _SimpleKey composite containing all arguments |
// Example usage:
final keyGen = DefaultKeyGenerator();
// Produces _SimpleKey.EMPTY
final key1 = keyGen.generate(target, method, MethodArgument.empty());
// Produces direct argument as key
final key2 = keyGen.generate(target, method, MethodArgument.positional(['user123']));
// Produces composite _SimpleKey
final key3 = keyGen.generate(target, method, MethodArgument.positional(['user123', 42]));
🧩 Extension and Customization
Developers can subclass KeyGenerator to override generate and implement custom strategies. This is common when integrating with:
- Domain identifiers (e.g., user IDs, tenant IDs)
- Cryptographic hashes or canonical string keys
- JSON-serializable key forms for distributed caching
Example:
final class JsonKeyGenerator extends KeyGenerator {
@override
Object generate(Object target, Method method, MethodArgument? argument) {
final args = argument?.toJson() ?? {};
return jsonEncode({'method': method.getName(), 'args': args});
}
}
📜 Contract and Design Rules
To ensure cache consistency and correctness:
- Determinism: The same inputs must always produce the same key.
- Equality: Generated keys must properly implement
==andhashCode. - Non-null guarantee: The generator must never return
null. - Performance: Key generation should be lightweight — no expensive I/O or computation.
- Stability: The key format should remain stable across library versions.
🚫 Common Pitfalls
- Returning mutable key objects that change after insertion
- Using
toString()for complex objects without ensuring stability - Ignoring named arguments in favor of positional-only logic
🔗 Related Components
SimpleKey— Default composite key type used for multi-argument invocations.- ConditionalKeyGenerator — Extended form that decides applicability dynamically.
- Cacheable, CachePut, CacheEvict — Annotations that rely on key generation for cache operation resolution.
KeyGenerator — Strategy for Cache Key Generation
The KeyGenerator defines a strategy for producing unique, stable, and
deterministic keys that represent specific method invocations.
These keys serve as identifiers for cache lookups, insertions, and evictions.
🔍 Purpose
In any caching mechanism, a key determines how cached entries are stored
and retrieved. The role of KeyGenerator is to translate a method invocation
— including its target object, the reflective Method representation, and
the runtime MethodArgument values — into a single canonical key object.
This abstraction allows for flexible strategies:
- Default keying behavior for simple cases
- Domain-specific key formats (e.g., string concatenation, hashing, encoding)
- Integration with frameworks that require consistent key generation semantics
⚙️ Default Behavior
The base implementation provides a deterministic fallback strategy:
| Case | Condition | Resulting Key |
|---|---|---|
| 1 | No arguments | _SimpleKey.EMPTY |
| 2 | Single argument (named or positional) | The single argument itself |
| 3 | Multiple arguments | A _SimpleKey composite containing all arguments |
// Example usage:
final keyGen = DefaultKeyGenerator();
// Produces _SimpleKey.EMPTY
final key1 = keyGen.generate(target, method, MethodArgument.empty());
// Produces direct argument as key
final key2 = keyGen.generate(target, method, MethodArgument.positional(['user123']));
// Produces composite _SimpleKey
final key3 = keyGen.generate(target, method, MethodArgument.positional(['user123', 42]));
🧩 Extension and Customization
Developers can subclass KeyGenerator to override generate and implement custom strategies. This is common when integrating with:
- Domain identifiers (e.g., user IDs, tenant IDs)
- Cryptographic hashes or canonical string keys
- JSON-serializable key forms for distributed caching
Example:
final class JsonKeyGenerator extends KeyGenerator {
@override
Object generate(Object target, Method method, MethodArgument? argument) {
final args = argument?.toJson() ?? {};
return jsonEncode({'method': method.getName(), 'args': args});
}
}
📜 Contract and Design Rules
To ensure cache consistency and correctness:
- Determinism: The same inputs must always produce the same key.
- Equality: Generated keys must properly implement
==andhashCode. - Non-null guarantee: The generator must never return
null. - Performance: Key generation should be lightweight — no expensive I/O or computation.
- Stability: The key format should remain stable across library versions.
🚫 Common Pitfalls
- Returning mutable key objects that change after insertion
- Using
toString()for complex objects without ensuring stability - Ignoring named arguments in favor of positional-only logic
🔗 Related Components
SimpleKey— Default composite key type used for multi-argument invocations.- ConditionalKeyGenerator — Extended form that decides applicability dynamically.
- Cacheable, CachePut, CacheEvict — Annotations that rely on key generation for cache operation resolution.
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
-
equalizedProperties(
) → List< Object?> -
Mixin-style contract for value-based equality,
hashCode, andtoString.inherited -
generate(
Object target, Method method, ExecutableArgument? argument) → Object - Generates a unique and deterministic cache key for the given method invocation.
-
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