class ClassOrDefaultProxyUtils {

    public static <T> T createProxy(Class<T> interfaceClass, String implementationClassName, Supplier<? extends T> defaultImplementation, ExceptionMapping<? extends Exception> ... exceptionMappings) {
        ObjectUtil.requireNotNull(interfaceClass, "interfaceClass can't be null");
        ObjectUtil.requireNotEmpty(implementationClassName, "implementationClassName can't be empty");
        ObjectUtil.requireNotNull(defaultImplementation, "defaultImplementation can't be null");

        try {
            final Class<?> implementationClazz = Class.forName(implementationClassName);
            final Object implementation = implementationClazz.getDeclaredConstructor().newInstance();
            return makeProxy(interfaceClass, implementation, true, exceptionMappings);
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
            log.warn("Implementation {} is not available, it will continue with default one {} : " + e.getLocalizedMessage(), implementationClassName, defaultImplementation);
        }

        return makeProxy(interfaceClass, defaultImplementation.get(), false, exceptionMappings);
    }

}