// Path: src/main/java/com/github/vbauer/caesar/runner/AsyncMethodRunner.java
// public interface AsyncMethodRunner {
// 
//     Method findSyncMethod(Object origin, Method asyncMethod);
// 
//     <T> Callable<T> createCall(Object origin, Method syncMethod, Object[] args);
// 
//     Object processResultFuture(Future<?> future, ExecutorService executor) throws Throwable;
// 
// }
// 
// Path: src/main/java/com/github/vbauer/caesar/runner/task/SimpleInvokeTask.java
// public class SimpleInvokeTask<T> implements Callable<T> {
// 
//     private final Method syncMethod;
//     private final Object[] args;
//     private final Object origin;
// 
// 
//     public SimpleInvokeTask(final Object origin, final Method syncMethod, final Object[] args) {
//         this.syncMethod = syncMethod;
//         this.args = args;
//         this.origin = origin;
//     }
// 
// 
//     @SuppressWarnings("unchecked")
//     public T call() throws Exception {
//         return (T) syncMethod.invoke(origin, args);
//     }
// 
// }
// 
// 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.runner.AsyncMethodRunner;
import com.github.vbauer.caesar.runner.task.SimpleInvokeTask;
import com.github.vbauer.caesar.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
package com.github.vbauer.caesar.runner.impl.base;



/**
 * @author Vladislav Bauer
 */

public abstract class AbstractAsyncMethodRunner implements AsyncMethodRunner {

    /**
     * {@inheritDoc}
     */
    @Override
    public final Method findSyncMethod(final Object origin, final Method asyncMethod) {
        final Class<?> targetClass = ReflectionUtils.getClassWithoutProxies(origin);
        final String methodName = asyncMethod.getName();

        final Class<?> returnType = asyncMethod.getReturnType();
        final Class<?>[] parameterTypes = asyncMethod.getParameterTypes();

        return findSyncMethod(targetClass, methodName, returnType, parameterTypes);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> Callable<T> createCall(
        final Object origin, final Method syncMethod, final Object[] args
    ) {
// Path: src/main/java/com/github/vbauer/caesar/runner/AsyncMethodRunner.java
// public interface AsyncMethodRunner {
// 
//     Method findSyncMethod(Object origin, Method asyncMethod);
// 
//     <T> Callable<T> createCall(Object origin, Method syncMethod, Object[] args);
// 
//     Object processResultFuture(Future<?> future, ExecutorService executor) throws Throwable;
// 
// }
// 
// Path: src/main/java/com/github/vbauer/caesar/runner/task/SimpleInvokeTask.java
// public class SimpleInvokeTask<T> implements Callable<T> {
// 
//     private final Method syncMethod;
//     private final Object[] args;
//     private final Object origin;
// 
// 
//     public SimpleInvokeTask(final Object origin, final Method syncMethod, final Object[] args) {
//         this.syncMethod = syncMethod;
//         this.args = args;
//         this.origin = origin;
//     }
// 
// 
//     @SuppressWarnings("unchecked")
//     public T call() throws Exception {
//         return (T) syncMethod.invoke(origin, args);
//     }
// 
// }
// 
// 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/impl/base/AbstractAsyncMethodRunner.java
import com.github.vbauer.caesar.runner.AsyncMethodRunner;
import com.github.vbauer.caesar.runner.task.SimpleInvokeTask;
import com.github.vbauer.caesar.util.ReflectionUtils;
import java.lang.reflect.Method;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;

package com.github.vbauer.caesar.runner.impl.base;



/**
 * @author Vladislav Bauer
 */

public abstract class AbstractAsyncMethodRunner implements AsyncMethodRunner {

    /**
     * {@inheritDoc}
     */
    @Override
    public final Method findSyncMethod(final Object origin, final Method asyncMethod) {
        final Class<?> targetClass = ReflectionUtils.getClassWithoutProxies(origin);
        final String methodName = asyncMethod.getName();

        final Class<?> returnType = asyncMethod.getReturnType();
        final Class<?>[] parameterTypes = asyncMethod.getParameterTypes();

        return findSyncMethod(targetClass, methodName, returnType, parameterTypes);
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <T> Callable<T> createCall(
        final Object origin, final Method syncMethod, final Object[] args
    ) {
        return new SimpleInvokeTask<>(origin, syncMethod, args);