CachingResourcePolicyResolver

A ResourcePolicyResolver decorator that memoizes the wrapped resolver's results, so resolution happens at most once per (principal, resource) for the lifetime of this instance.

A single response can serialize many @IhawuResource objects (a list endpoint, a nested graph); without caching, the underlying resolver would be invoked once per object — wasteful, and unsafe if the backing store changes mid-response, which could mask two objects in the same document under different policies. This decorator resolves each key once and reuses the result, including the empty "no policy applies" result.

Scope is the instance lifetime. The cache is held in this object and dies with it; the core never refers to "request." Callers control scope by controlling the instance — create one per request (e.g. a request-scoped bean in the Spring starter) for request-scoped caching with automatic freshness between requests. A single shared instance caches application-wide and can serve stale policy; that is a deliberate misuse, not the intended pattern.

Memoization uses ConcurrentHashMap.computeIfAbsent, so the wrapped resolver is invoked at most once per key even under concurrent serialization. The result is returned by reference and not copied; callers must honour the read-only List contract and not mutate it.

See also

Samples

// A resolver that records how often it is consulted.
var calls = 0
val counting =
    object : ResourcePolicyResolver {
        override fun resolve(
            principal: IhawuPrincipal,
            resource: String,
        ): List<FieldPolicy> {
            calls++
            return listOf(FieldPolicy("salary", MaskingStrategy.REDACT, "***"))
        }
    }

// Wrap it: within one instance, repeated resolves of the same key hit the delegate once.
val resolver = CachingResourcePolicyResolver(counting)
val principal = IhawuPrincipal("u1", roles = setOf("MANAGER"), attributes = emptyMap())

resolver.resolve(principal, "employee")
resolver.resolve(principal, "employee")

check(calls == 1) // resolved once; the second call is served from the cache

Constructors

Link copied to clipboard
constructor(delegate: ResourcePolicyResolver)

Functions

Link copied to clipboard
open override fun resolve(principal: IhawuPrincipal, resource: String): List<FieldPolicy>

Resolves the resource field policies that apply when principal requests resource.