class SingleAccessMethodCompiler {

    public static <T> T compileSingleAccessMethod(String suggestedClassName, Class<T> interfaceType, MethodHandle methodHandle)
    {
        ClassDefinition classDefinition = new ClassDefinition(
                a(PUBLIC, FINAL, SYNTHETIC),
                makeClassName(suggestedClassName),
                type(Object.class),
                type(interfaceType));

        classDefinition.declareDefaultConstructor(a(PUBLIC));

        Method method = getSingleAbstractMethod(interfaceType);
        Class<?>[] parameterTypes = method.getParameterTypes();
        MethodHandle adaptedMethodHandle = methodHandle.asType(methodType(method.getReturnType(), parameterTypes));

        List<io.airlift.bytecode.Parameter> parameters = new ArrayList<>();
        for (int i = 0; i < parameterTypes.length; i++) {
            parameters.add(arg("arg" + i, parameterTypes[i]));
        }

        MethodDefinition methodDefinition = classDefinition.declareMethod(
                a(PUBLIC),
                method.getName(),
                type(method.getReturnType()),
                parameters);

        CallSiteBinder callSiteBinder = new CallSiteBinder();
        BytecodeExpression invocation = invokeDynamic(
                BOOTSTRAP_METHOD,
                ImmutableList.of(callSiteBinder.bind(adaptedMethodHandle).getBindingId()),
                method.getName(),
                method.getReturnType(),
                parameters);
        if (method.getReturnType() != void.class) {
            invocation = invocation.ret();
        }
        methodDefinition.getBody().append(invocation);
        // note this will not work if interface class is not visible from this class loader,
        // but we must use this class loader to ensure the bootstrap method is visible
        ClassLoader classLoader = SingleAccessMethodCompiler.class.getClassLoader();
        Class<? extends T> newClass = defineClass(classDefinition, interfaceType, callSiteBinder.getBindings(), classLoader);
        try {
            T instance = newClass
                    .getDeclaredConstructor()
                    .newInstance();
            return instance;
        }
        catch (ReflectiveOperationException e) {
            throw new RuntimeException(e);
        }
    }

    private  SingleAccessMethodCompiler();

}