18 — Advanced

Type References

Java erases generic type information at runtime. TypeReference solves this by using the anonymous subclass pattern to capture and preserve generic type information, so rulii can work with fully parameterized types like List<String> or Map<String, Integer>.

The Problem

Without TypeReference, generic type information is lost at runtime:

// Without TypeReference — type info is lost
bindings.bind("tags", new ArrayList<String>());
// Binding type is just ArrayList, not ArrayList<String>

The Solution

Use TypeReference to preserve the full generic type:

// With TypeReference — generic type is preserved
bindings.bind("tags", new TypeReference<List<String>>() {}, new ArrayList<>());
// Binding type is List<String>

// Check the captured type
Binding<List<String>> binding = bindings.getBinding("tags");
Type type = binding.getType();  // java.util.List<java.lang.String>

When to Use TypeReference

Use TypeReference whenever you need type-safe bindings with generic types:

List<T>

Preserve element type for lists

Map<K, V>

Preserve key and value types for maps

Optional<T>

Preserve wrapped type for optionals

Custom Generics

Any parameterized type you define

Programmatic Type Creation

Use TypeReference.with(Type) when you already have a Type instance and need to wrap it in a TypeReference:

// Factory method for programmatic type creation
Type existingType = /* obtained via reflection */;
TypeReference<?> ref = TypeReference.with(existingType);

Integration

TypeReference integrates with the rest of rulii's type system. When bindings have accurate generic type information, the framework can perform correct parameter matching and automatic type conversion, ensuring that values are passed to conditions, actions, and functions with the right types.