// Path: src/main/java/com/github/vbauer/caesar/util/ReflectionUtils.java
// @SuppressWarnings("unchecked")
// public final class ReflectionUtils {
// 
//     public static final String PACKAGE_SEPARATOR = ".";
//     
// 
//     private ReflectionUtils() {
//         throw new UnsupportedOperationException();
//     }
// 
// 
//     public static <T> Class<T> getClassWithoutProxies(final Object object) {
//         try {
//             // XXX: Use HibernateProxyHelper to un-proxy object and get the original class.
//             return (Class<T>) Class.forName("org.hibernate.proxy.HibernateProxyHelper")
//                 .getDeclaredMethod("getClassWithoutInitializingProxy", Object.class)
//                 .invoke(null, object);
//         } catch (final Exception ex) {
//             return getClassSafe(object);
//         }
//     }
// 
//     public static <T> Class<T> getClassSafe(final Object object) {
//         return object != null ? (Class<T>) object.getClass() : null;
//     }
// 
//     public static <T> T createObject(final String className) {
//         try {
//             final Class<?> clazz = Class.forName(className);
//             return (T) clazz.newInstance();
//         } catch (final Throwable ex) {
//             return null;
//         }
//     }
// 
//     public static <T> Collection<T> createObjects(final Collection<String> classNames) {
//         final List<T> objects = new ArrayList<>();
//         for (final String className : classNames) {
//             final T object = createObject(className);
//             if (object != null) {
//                 objects.add(object);
//             }
//         }
//         return objects;
//     }
//     
//     public static Collection<String> classNames(final String packageName, final Collection<String> classNames) {
//         final List<String> result = new ArrayList<>();
//         for (final String className : classNames) {
//             result.add(packageName + PACKAGE_SEPARATOR + className);
//         }
//         return result;        
//     }
// 
//     public static Method findDeclaredMethod(
//         final Class<?> objectClass, final String methodName, final Class<?>[] parameterTypes
//     ) {
//         try {
//             return objectClass.getDeclaredMethod(methodName, parameterTypes);
//         } catch (final Throwable ignored) {
//             return null;
//         }
//     }
// 
//     public static <T extends Annotation> T findAnnotationFromMethodOrClass(
//         final Method method, final Class<T> annotationClass
//     ) {
//         final T annotation = method.getAnnotation(annotationClass);
//         if (annotation != null) {
//             return annotation;
//         }
// 
//         final Class<?> originClass = method.getDeclaringClass();
//         return originClass.getAnnotation(annotationClass);
//     }
// 
// }


import com.github.vbauer.caesar.util.ReflectionUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
package com.github.vbauer.caesar.runner;



/**
 * @author Vladislav Bauer 
 */

public final class AsyncMethodRunnerFactory {

    public static final String PACKAGE_NAME = "com.github.vbauer.caesar.runner.impl";

    /**
     * Immutable list with class names of method runners.
     *
     * IMPORTANT:
     * This classes must be listed in the right order: from more-specific to less-specific classes.
     */
    public static final List<String> CLASS_NAMES = Collections.unmodifiableList(
        Arrays.asList(
            "ObservableMethodRunner",
            "ListenableFutureMethodRunner",
            "FutureCallbackMethodRunner",
            "FutureMethodRunner",
            "AsyncCallbackMethodRunner",
            "SyncMethodRunner"
        )
    );
    

    private AsyncMethodRunnerFactory() {
        throw new UnsupportedOperationException();
    }


    public static Collection<AsyncMethodRunner> createMethodRunners() {
        final Collection<String> classNames =
            ReflectionUtils.classNames(PACKAGE_NAME, CLASS_NAMES);
        
// Path: src/main/java/com/github/vbauer/caesar/util/ReflectionUtils.java
// @SuppressWarnings("unchecked")
// public final class ReflectionUtils {
// 
//     public static final String PACKAGE_SEPARATOR = ".";
//     
// 
//     private ReflectionUtils() {
//         throw new UnsupportedOperationException();
//     }
// 
// 
//     public static <T> Class<T> getClassWithoutProxies(final Object object) {
//         try {
//             // XXX: Use HibernateProxyHelper to un-proxy object and get the original class.
//             return (Class<T>) Class.forName("org.hibernate.proxy.HibernateProxyHelper")
//                 .getDeclaredMethod("getClassWithoutInitializingProxy", Object.class)
//                 .invoke(null, object);
//         } catch (final Exception ex) {
//             return getClassSafe(object);
//         }
//     }
// 
//     public static <T> Class<T> getClassSafe(final Object object) {
//         return object != null ? (Class<T>) object.getClass() : null;
//     }
// 
//     public static <T> T createObject(final String className) {
//         try {
//             final Class<?> clazz = Class.forName(className);
//             return (T) clazz.newInstance();
//         } catch (final Throwable ex) {
//             return null;
//         }
//     }
// 
//     public static <T> Collection<T> createObjects(final Collection<String> classNames) {
//         final List<T> objects = new ArrayList<>();
//         for (final String className : classNames) {
//             final T object = createObject(className);
//             if (object != null) {
//                 objects.add(object);
//             }
//         }
//         return objects;
//     }
//     
//     public static Collection<String> classNames(final String packageName, final Collection<String> classNames) {
//         final List<String> result = new ArrayList<>();
//         for (final String className : classNames) {
//             result.add(packageName + PACKAGE_SEPARATOR + className);
//         }
//         return result;        
//     }
// 
//     public static Method findDeclaredMethod(
//         final Class<?> objectClass, final String methodName, final Class<?>[] parameterTypes
//     ) {
//         try {
//             return objectClass.getDeclaredMethod(methodName, parameterTypes);
//         } catch (final Throwable ignored) {
//             return null;
//         }
//     }
// 
//     public static <T extends Annotation> T findAnnotationFromMethodOrClass(
//         final Method method, final Class<T> annotationClass
//     ) {
//         final T annotation = method.getAnnotation(annotationClass);
//         if (annotation != null) {
//             return annotation;
//         }
// 
//         final Class<?> originClass = method.getDeclaringClass();
//         return originClass.getAnnotation(annotationClass);
//     }
// 
// }


// Path: src/main/java/com/github/vbauer/caesar/runner/AsyncMethodRunnerFactory.java
import com.github.vbauer.caesar.util.ReflectionUtils;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

package com.github.vbauer.caesar.runner;



/**
 * @author Vladislav Bauer 
 */

public final class AsyncMethodRunnerFactory {

    public static final String PACKAGE_NAME = "com.github.vbauer.caesar.runner.impl";

    /**
     * Immutable list with class names of method runners.
     *
     * IMPORTANT:
     * This classes must be listed in the right order: from more-specific to less-specific classes.
     */
    public static final List<String> CLASS_NAMES = Collections.unmodifiableList(
        Arrays.asList(
            "ObservableMethodRunner",
            "ListenableFutureMethodRunner",
            "FutureCallbackMethodRunner",
            "FutureMethodRunner",
            "AsyncCallbackMethodRunner",
            "SyncMethodRunner"
        )
    );
    

    private AsyncMethodRunnerFactory() {
        throw new UnsupportedOperationException();
    }


    public static Collection<AsyncMethodRunner> createMethodRunners() {
        final Collection<String> classNames =
            ReflectionUtils.classNames(PACKAGE_NAME, CLASS_NAMES);
        
        return ReflectionUtils.createObjects(classNames);