// Path: src/main/java/ru/vyarus/guice/ext/core/util/Utils.java
// public final class Utils {
// 
//     private Utils() {
//     }
// 
//     /**
//      * Important check, because JDK proxies of public interfaces have no package
//      * (thanks to @binkley https://github.com/99soft/lifegycle/pull/5).
//      *
//      * @param type class type to check
//      * @return true if package could be resolved, false otherwise
//      */
//     public static boolean isPackageValid(final Class type) {
//         boolean res = false;
//         if (type != null) {
//             final Package packaj = type.getPackage();
//             res = !(packaj == null || packaj.getName().startsWith("java"));
//         }
//         return res;
//     }
// 
//     /**
//      * Checks that method has no parameters, otherwise throws exception.
//      *
//      * @param method method to check
//      */
//     public static void checkNoParams(final Method method) {
//         if (method.getParameterTypes().length > 0) {
//             throw new IllegalStateException("Method without parameters required");
//         }
//     }
// 
//     /**
//      * Note: versions below 1.8 are not supported.
//      *
//      * @return true if current java is 1.8, otherwise assumed 9 or above
//      */
//     public static boolean isJava8() {
//         final String version = System.getProperty("java.version");
//         return version.startsWith("1.8");
//     }
// }


import com.google.common.base.Preconditions;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.ProvidedBy;
import com.google.inject.internal.Annotations;
import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import ru.vyarus.guice.ext.core.util.Utils;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;

        /*
         * Synchronization is required to avoid double generation and consequent problems.
         * Very unlikely that this method would be called too often and synchronization become bottleneck.
         * Using original class as monitor to allow concurrent generation for different classes.
         */
        synchronized (type) {
            Class<?> targetClass;
            try {
                // will work if class was already generated
                targetClass = classLoader.loadClass(targetClassName);
            } catch (ClassNotFoundException ex) {
                targetClass = generateClass(type, targetClassName, classLoader, scope, anchor);
            }
            return (Class<T>) targetClass;
        }
    }

    private static Class<?> generateClass(final Class<?> type, final String targetClassName,
                                          final ClassLoader classLoader,
                                          final Class<? extends java.lang.annotation.Annotation> scope,
                                          final Class<?> anchor) {
        try {
            // have to use custom pool because original type classloader could be thrown away
            // and all cached CtClass objects would be stale
            final ClassPool classPool = new ClassPool();
            classPool.appendClassPath(new LoaderClassPath(classLoader));

            final CtClass impl = generateCtClass(classPool, targetClassName, type, scope, anchor);
            // incompatible javassist apis for java 8 and >=9
// Path: src/main/java/ru/vyarus/guice/ext/core/util/Utils.java
// public final class Utils {
// 
//     private Utils() {
//     }
// 
//     /**
//      * Important check, because JDK proxies of public interfaces have no package
//      * (thanks to @binkley https://github.com/99soft/lifegycle/pull/5).
//      *
//      * @param type class type to check
//      * @return true if package could be resolved, false otherwise
//      */
//     public static boolean isPackageValid(final Class type) {
//         boolean res = false;
//         if (type != null) {
//             final Package packaj = type.getPackage();
//             res = !(packaj == null || packaj.getName().startsWith("java"));
//         }
//         return res;
//     }
// 
//     /**
//      * Checks that method has no parameters, otherwise throws exception.
//      *
//      * @param method method to check
//      */
//     public static void checkNoParams(final Method method) {
//         if (method.getParameterTypes().length > 0) {
//             throw new IllegalStateException("Method without parameters required");
//         }
//     }
// 
//     /**
//      * Note: versions below 1.8 are not supported.
//      *
//      * @return true if current java is 1.8, otherwise assumed 9 or above
//      */
//     public static boolean isJava8() {
//         final String version = System.getProperty("java.version");
//         return version.startsWith("1.8");
//     }
// }


// Path: src/main/java/ru/vyarus/guice/ext/core/generator/DynamicClassGenerator.java
import com.google.common.base.Preconditions;
import com.google.inject.ImplementedBy;
import com.google.inject.Inject;
import com.google.inject.ProvidedBy;
import com.google.inject.internal.Annotations;
import javassist.*;
import javassist.bytecode.*;
import javassist.bytecode.annotation.Annotation;
import ru.vyarus.guice.ext.core.util.Utils;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;


        /*
         * Synchronization is required to avoid double generation and consequent problems.
         * Very unlikely that this method would be called too often and synchronization become bottleneck.
         * Using original class as monitor to allow concurrent generation for different classes.
         */
        synchronized (type) {
            Class<?> targetClass;
            try {
                // will work if class was already generated
                targetClass = classLoader.loadClass(targetClassName);
            } catch (ClassNotFoundException ex) {
                targetClass = generateClass(type, targetClassName, classLoader, scope, anchor);
            }
            return (Class<T>) targetClass;
        }
    }

    private static Class<?> generateClass(final Class<?> type, final String targetClassName,
                                          final ClassLoader classLoader,
                                          final Class<? extends java.lang.annotation.Annotation> scope,
                                          final Class<?> anchor) {
        try {
            // have to use custom pool because original type classloader could be thrown away
            // and all cached CtClass objects would be stale
            final ClassPool classPool = new ClassPool();
            classPool.appendClassPath(new LoaderClassPath(classLoader));

            final CtClass impl = generateCtClass(classPool, targetClassName, type, scope, anchor);
            // incompatible javassist apis for java 8 and >=9
            return Utils.isJava8() ? impl.toClass(classLoader, type.getProtectionDomain()) : impl.toClass(type);