KeyGenerator class abstract interface

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:

  1. Determinism: The same inputs must always produce the same key.
  2. Equality: Generated keys must properly implement == and hashCode.
  3. Non-null guarantee: The generator must never return null.
  4. Performance: Key generation should be lightweight — no expensive I/O or computation.
  5. 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
  • 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:

  1. Determinism: The same inputs must always produce the same key.
  2. Equality: Generated keys must properly implement == and hashCode.
  3. Non-null guarantee: The generator must never return null.
  4. Performance: Key generation should be lightweight — no expensive I/O or computation.
  5. 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
  • 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.
Implementers

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, and toString.
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