code: @SuppressWarnings("unchecked")
    public <T extends VALUE> T withCaching(KEY key, Supplier<VALUE> cacheableOperation) {
  
      Assert.notNull(key, "Key is required");
      Assert.notNull(cacheableOperation, "Supplier is required");
  
      ReadWriteLock lock = getLock();
  
      return (T) Optional.ofNullable(read(lock, key)).orElseGet(() ->
        Optional.ofNullable(cacheableOperation.get())
          .map(value -> write(lock, key, value))
          .orElse(null));
    }
docs: Implementation of the look-aside cache pattern.
  
  This caching data access operation first attempts to locate an entry in the {@link Cache}
  with the given {@link KEY key}, returning the {@link VALUE value} of the entry if present.
  
  If an entry with the given {@link KEY key} is not present in the {@link Cache} then the supplied
  {@link Supplier cacheable operation} is invoked to compute or load a {@link VALUE value}
  and put into the {@link Cache} as an entry mapped by the given {@link KEY key}; this operation
  completes by returning the {@link VALUE result} of the {@link Supplier cacheable operation}.
  
  @param <T> {@link Class type} of the return {@link VALUE value}.
  @param key {@link KEY key} used to identify the {@link Cache} entry containing the {@link VALUE} to lookup.
  @param cacheableOperation {@link Supplier} used to compute or load a {@link VALUE value}
  for given {@link KEY key} if the cacheable data access operation initially results in a cache miss.
  @return the cached {@link VALUE value} for the given {@link KEY key} in the {@link Cache} if present,
  or returns the {@link VALUE value} supplied by invoking the {@link Supplier cacheable operation}.
  @throws IllegalArgumentException if either the {@link KEY key} or the {@link Supplier} are {@literal null}.
  @see java.util.function.Supplier
  @see #getCache()
  @see #getLock()