class JCacheProxyManager<K> extends AbstractProxyManager<K> {

    private static final Map<String, String> incompatibleProviders = Collections.emptyMap();
    static {
        // incompatibleProviders.put("org.infinispan", " use module bucket4j-infinispan directly");
    }

    private static final Set<String> preferLambdaStyleProviders = Collections.singleton("org.infinispan");

    private final Cache<K, byte[]> cache;
    private final boolean preferLambdaStyle;

    public JCacheProxyManager(Cache<K, byte[]> cache) {
        this(cache, ClientSideConfig.getDefault());
    }

    public JCacheProxyManager(Cache<K, byte[]> cache, ClientSideConfig clientSideConfig) {
        super(clientSideConfig);
        checkCompatibilityWithProvider(cache);
        this.cache = Objects.requireNonNull(cache);
        this.preferLambdaStyle = preferLambdaStyle(cache);
    }

    @Override
    public <T> CommandResult<T> execute(K key, Request<T> request) {
        EntryProcessor<K, byte[], byte[]> entryProcessor = preferLambdaStyle? createLambdaProcessor(request) : new BucketProcessor<>(request);
        byte[] resultBytes = cache.invoke(key, entryProcessor);
        return InternalSerializationHelper.deserializeResult(resultBytes, request.getBackwardCompatibilityVersion());
    }

    @Override
    public void removeProxy(K key) {
        cache.remove(key);
    }

    @Override
    public boolean isAsyncModeSupported() {
        return false;
    }

    @Override
    public <T> CompletableFuture<CommandResult<T>> executeAsync(K key, Request<T> request) {<FILL_FUNCTION_BODY>}

    @Override
    protected CompletableFuture<Void> removeAsync(K key) {
        // because JCache does not specify async API
        throw new UnsupportedOperationException();
    }

    private void checkCompatibilityWithProvider(Cache<K, byte[]> cache) {
        CacheManager cacheManager = cache.getCacheManager();
        if (cacheManager == null) {
            return;
        }

        CachingProvider cachingProvider = cacheManager.getCachingProvider();
        if (cachingProvider == null) {
            return;
        }

        String providerClassName = cachingProvider.getClass().getName();
        incompatibleProviders.forEach((providerPrefix, recommendation) -> {
            if (providerClassName.startsWith(providerPrefix)) {
                String message = "The Cache provider " + providerClassName + " is incompatible with Bucket4j, " + recommendation;
                throw new UnsupportedOperationException(message);
            }
        });
    }

    private boolean preferLambdaStyle(Cache<K, byte[]> cache) {
        CacheManager cacheManager = cache.getCacheManager();
        if (cacheManager == null) {
            return false;
        }

        CachingProvider cachingProvider = cacheManager.getCachingProvider();
        if (cachingProvider == null) {
            return false;
        }

        String providerClassName = cachingProvider.getClass().getName();
        for (String providerPrefix : preferLambdaStyleProviders) {
            if (providerClassName.startsWith(providerPrefix)) {
                return true;
            }
        }

        return false;
    }

    public <T> EntryProcessor<K, byte[], byte[]> createLambdaProcessor(Request<T> request) {
        byte[] serializedRequest = InternalSerializationHelper.serializeRequest(request);
        return  (Serializable & EntryProcessor<K, byte[], byte[]>) (mutableEntry, objects)
                -> new JCacheTransaction(mutableEntry, serializedRequest).execute();
    }

    private static class BucketProcessor<K, T> implements Serializable, EntryProcessor<K, byte[], byte[]> {

        private static final long serialVersionUID = 911;

        private final byte[] serializedRequest;

        public BucketProcessor(Request<T> request) {
            this.serializedRequest = InternalSerializationHelper.serializeRequest(request);
        }

        @Override
        public byte[] process(MutableEntry<K, byte[]> mutableEntry, Object... arguments) {
            return new JCacheTransaction(mutableEntry, serializedRequest).execute();
        }

    }

    private static class JCacheTransaction extends AbstractBinaryTransaction {

        private final MutableEntry<?, byte[]> targetEntry;

        private JCacheTransaction(MutableEntry<?, byte[]> targetEntry, byte[] requestBytes) {
            super(requestBytes);
            this.targetEntry = targetEntry;
        }

        @Override
        public boolean exists() {
            return targetEntry.exists();
        }

        @Override
        protected byte[] getRawState() {
            return targetEntry.getValue();
        }

        @Override
        protected void setRawState(byte[] newStateBytes, RemoteBucketState newState) {
            targetEntry.setValue(newStateBytes);
        }

    }

}

        // because JCache does not specify async API
        throw new UnsupportedOperationException();
    
<methods>public AsyncProxyManager<K> asAsync() ,public RemoteBucketBuilder<K> builder() ,public Optional<io.github.bucket4j.BucketConfiguration> getProxyConfiguration(K) <variables>private static final io.github.bucket4j.distributed.proxy.RecoveryStrategy DEFAULT_RECOVERY_STRATEGY,private static final io.github.bucket4j.distributed.proxy.optimization.Optimization DEFAULT_REQUEST_OPTIMIZER,private AsyncProxyManager<K> asyncView,private final non-sealed io.github.bucket4j.distributed.proxy.ClientSideConfig clientSideConfig