docs: protected Object interceptCompletableFuture(MethodInvocationContext<Object, Object> context, ReturnType<?> returnTypeObject, Class returnType) {
          CacheOperation cacheOperation = new CacheOperation(context, returnType);
          AnnotationValue<Cacheable> cacheable = cacheOperation.cacheable;
          CompletableFuture<Object> returnFuture;
          if (cacheable != null) {
              AsyncCache<?> asyncCache = cacheManager.getCache(cacheOperation.cacheableCacheName).async();
              CacheKeyGenerator keyGenerator = resolveKeyGenerator(cacheOperation.defaultKeyGenerator, cacheable);
              Object[] params = resolveParams(context, cacheable.get(MEMBER_PARAMETERS, String[].class, StringUtils.EMPTY_STRING_ARRAY));
              Object key = keyGenerator.generateKey(context, params);
              CompletableFuture<Object> thisFuture = new CompletableFuture<>();
              Argument<?> firstTypeVariable = returnTypeObject.getFirstTypeVariable().orElse(Argument.of(Object.class));
              asyncCache.get(key, firstTypeVariable).whenComplete((BiConsumer<Optional<?>, Throwable>) (o, throwable) -> {
                  if (throwable == null && o.isPresent()) {
                      // cache hit, return result
                      if (LOG.isDebugEnabled()) {
                          LOG.debug("Value found in cache [" + asyncCache.getName() + "] for invocation: " + context);
                      }
                      thisFuture.complete(o.get());
                  } else {
                      // cache miss proceed with original future
                      try {
                          if (throwable != null) {
                              if (errorHandler.handleLoadError(asyncCache, key, asRuntimeException(throwable))) {
                                  thisFuture.completeExceptionally(throwable);
                                  return;
                              }
                          }
                          CompletableFuture<?> completableFuture = (CompletableFuture) context.proceed();
                          if (completableFuture == null) {
                              thisFuture.complete(null);
                          } else {
                              completableFuture.whenComplete((BiConsumer<Object, Throwable>) (o1, t2) -> {
                                  if (t2 != null) {
                                      thisFuture.completeExceptionally(t2);
                                  } else {
                                      // new cacheable result, cache it
                                      asyncCache.put(key, o1).whenComplete((aBoolean, throwable1) -> {
                                          if (throwable1 == null) {
                                              thisFuture.complete(o1);
                                          } else {
                                              thisFuture.completeExceptionally(throwable1);
                                          }
                                      });
  
                                  }
                              });
                          }
                      } catch (RuntimeException e) {
                          thisFuture.completeExceptionally(e);
                      }
                  }
              });
              returnFuture = thisFuture;
          } else {
              returnFuture = (CompletableFuture<Object>) context.proceed();
          }
          if (cacheOperation.hasWriteOperations()) {
              returnFuture = processFuturePutOperations(context, cacheOperation, returnFuture);
          }
          return returnFuture;
      }