class WrapperGenerator implements IWrapperGenerator {

    @Override
    public <T> T generate(final Class<T> targetInterface)
            throws InvalidArgumentException, WrapperGeneratorException {
        T instance = null;

        if (null == targetInterface) {
            throw new InvalidArgumentException("Target class should not be null!");
        }
        if (!targetInterface.isInterface()) {
            throw new InvalidArgumentException("Target class should be an interface!");
        }

        try {
            instance = IOC.resolve(
                    IOC.resolve(IOC.getKeyForKeyStorage(), targetInterface.getCanonicalName() + "wrapper")
            );
        } catch (ResolutionException e) {
            // do nothing
            // ToDo: need refactoring
        }
        if (null != instance) {
            return instance;
        }

        try {
            Class<T> clazz = generateClass(targetInterface);

            // May be later CreateNewInstanceStrategy will be replaced by GetInstanceFromPoolStrategy
            // ToDo: replace this strategy to the future plugin for WrapperGenerator
            IOC.register(
                    IOC.resolve(IOC.getKeyForKeyStorage(), targetInterface.getCanonicalName() + "wrapper"),
                    new ApplyFunctionToArgumentsStrategy(
                            (arg) ->  {
                                try {
                                    return clazz.newInstance();
                                } catch (Throwable e) {
                                    throw new RuntimeException("Error on creation new instance.", e);
                                }
                            }
                    )
            );

            return IOC.resolve(
                    IOC.resolve(IOC.getKeyForKeyStorage(), targetInterface.getCanonicalName() + "wrapper")
            );
        } catch (Throwable e) {
            throw new WrapperGeneratorException(
                    "Could not implement wrapper interface because of the following error:",
                    e
            );
        }
    }

    public  WrapperGenerator(final ClassLoader classLoader);

}