package com.googlecode.totallylazy.reflection;
import com.googlecode.totallylazy.*;
import com.googlecode.totallylazy.functions.Function1;
import com.googlecode.totallylazy.predicates.LogicalPredicate;
import sun.reflect.generics.repository.MethodRepository;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import static com.googlecode.totallylazy.Callers.call;
import static com.googlecode.totallylazy.Classes.allClasses;
import static com.googlecode.totallylazy.Exceptions.handleException;
import static com.googlecode.totallylazy.predicates.Predicates.instanceOf;
import static com.googlecode.totallylazy.Sequences.sequence;
public class Methods {
public static Method method(String internalName, String name, String descriptior) throws ClassNotFoundException {
Class<?> aClass = Class.forName(internalName.replace('/', '.'));
MethodRepository repository = MethodRepository.make(descriptior, Signature.genericsFactory(aClass));
Sequence<Type> parameterTypes = sequence(repository.getParameterTypes());
Type returnType = repository.getReturnType();
return sequence(aClass.getMethods()).
filter(m -> m.getName().equals(name)).
filter(m -> m.getReturnType().equals(returnType)).
filter(m -> sequence(m.getParameterTypes()).equals(parameterTypes)).
head();
}
public static Function1<Method, String> methodName() {
return Method::getName;
}
public static Function1<Method,? extends Class<?>> returnType() {
return Method::getReturnType;
}
public static Function1<Method, Class<?>[]> parameterTypes() {
return Method::getParameterTypes;
}
public static <T extends Annotation> Function1<Method, T> annotation(final Class<T> annotationClass) {
return method -> method.getAnnotation(annotationClass);
}
public static Function1<Method, Type> genericReturnType() {
return Method::getGenericReturnType;
}
public static Function1<Method, Type[]> genericParameterTypes() {
return Method::getGenericParameterTypes;
}
public static LogicalPredicate<Method> modifier(final int modifier) {
return new LogicalPredicate<Method>() {
public boolean matches(Method method) {
return (method.getModifiers() & modifier) != 0;
}
};
}
public static Function1<Class<?>, Method> method(final String name, final Class<?>... parameters) {
return aClass -> aClass.getMethod(name, parameters);
}
public static <T> Option<Method> method(T instance, final String name, final Class<?>... parameters) {
return method(instance.getClass(), name, parameters);
}
public static Option<Method> method(Class<?> aClass, String name, final Class<?>... parameters) {
return call(handleException(method(name, parameters), instanceOf(NoSuchMethodException.class)), aClass);
}
public static Function1<Class<?>, Iterable<Method>> methods() {
return aClass -> sequence(aClass.getMethods());
}
public static Function1<Class<?>, Iterable<Method>> declaredMethods() {
return aClass -> sequence(aClass.getDeclaredMethods());
}
public static Sequence<Method> allMethods(Class<?> aClass) {
return allClasses(aClass).flatMap(Methods.declaredMethods());
}
public static <T, R> R invoke(Method method, T instance, Object... arguments) {
try {
method.setAccessible(true);
return Unchecked.cast(method.invoke(instance, arguments));
} catch (IllegalAccessException | InvocationTargetException e) {
throw LazyException.lazyException(e);
}
}
public static <R> Function1<Method, R> invokeOn(final Object instance, final Object... arguments) {
return method -> Unchecked.cast(invoke(method, instance, arguments));
}
}