class FutureSyncInvocationHandler extends AbstractInvocationHandler {

    private final StatefulConnection<?, ?> connection;

    private final TimeoutProvider timeoutProvider;

    private final Object asyncApi;

    private final MethodTranslator translator;

    FutureSyncInvocationHandler(StatefulConnection<?, ?> connection, Object asyncApi, Class<?>[] interfaces) {
        this.connection = connection;
        this.timeoutProvider = new TimeoutProvider(() -> connection.getOptions().getTimeoutOptions(),
                () -> connection.getTimeout().toNanos());
        this.asyncApi = asyncApi;
        this.translator = MethodTranslator.of(asyncApi.getClass(), interfaces);
    }

    @Override
    protected Object handleInvocation(Object proxy, Method method, Object[] args) throws Throwable {<FILL_FUNCTION_BODY>}

    private long getTimeoutNs(RedisFuture<?> command) {

        if (command instanceof RedisCommand) {
            return timeoutProvider.getTimeoutNs((RedisCommand) command);
        }

        return connection.getTimeout().toNanos();
    }

    private static boolean isTransactionActive(StatefulConnection<?, ?> connection) {
        return connection instanceof StatefulRedisConnection && ((StatefulRedisConnection) connection).isMulti();
    }

    private static boolean isTxControlMethod(String methodName, Object[] args) {

        if (methodName.equals("exec") || methodName.equals("multi") || methodName.equals("discard")) {
            return true;
        }

        if (methodName.equals("dispatch") && args.length > 0 && args[0] instanceof ProtocolKeyword) {

            ProtocolKeyword keyword = (ProtocolKeyword) args[0];
            if (keyword.name().equals(CommandType.MULTI.name()) || keyword.name().equals(CommandType.EXEC.name())
                    || keyword.name().equals(CommandType.DISCARD.name())) {
                return true;
            }
        }

        return false;
    }

}


        try {

            Method targetMethod = this.translator.get(method);
            Object result = targetMethod.invoke(asyncApi, args);

            if (result instanceof RedisFuture<?>) {

                RedisFuture<?> command = (RedisFuture<?>) result;

                if (!isTxControlMethod(method.getName(), args) && isTransactionActive(connection)) {
                    return null;
                }

                long timeout = getTimeoutNs(command);

                return Futures.awaitOrCancel(command, timeout, TimeUnit.NANOSECONDS);
            }

            return result;
        } catch (InvocationTargetException e) {
            throw e.getTargetException();
        }
    
<methods>public non-sealed void <init>() ,public boolean equals(java.lang.Object) ,public int hashCode() ,public final java.lang.Object invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[]) throws java.lang.Throwable,public java.lang.String toString() <variables>private static final java.lang.Object[] NO_ARGS