/*
* Copyright (c) 2006 Rogério Liesenfeld
* This file is subject to the terms of the MIT license (see LICENSE.txt).
*/
package mockit.internal.reflection;
import java.lang.reflect.*;
import javax.annotation.*;
import mockit.internal.util.*;
public final class RealMethodOrConstructor
{
@Nonnull public final Member member;
public RealMethodOrConstructor(@Nonnull String classDesc, @Nonnull String methodName, @Nonnull String methodDesc)
throws NoSuchMethodException
{
ClassLoader cl = getClass().getClassLoader();
Class<?> realClass = ClassLoad.loadFromLoader(cl, classDesc.replace('/', '.'));
if (methodName.charAt(0) == '<') {
member = findConstructor(realClass, methodDesc);
}
else {
member = findMethod(realClass, methodName, methodDesc);
}
}
public RealMethodOrConstructor(@Nonnull String className, @Nonnull String methodNameAndDesc)
throws NoSuchMethodException
{
this(ClassLoad.loadFromLoader(RealMethodOrConstructor.class.getClassLoader(), className), methodNameAndDesc);
}
public RealMethodOrConstructor(@Nonnull Class<?> realClass, @Nonnull String methodNameAndDesc)
throws NoSuchMethodException
{
int p = methodNameAndDesc.indexOf('(');
String memberDesc = methodNameAndDesc.substring(p);
if (methodNameAndDesc.charAt(0) == '<') {
member = findConstructor(realClass, memberDesc);
}
else {
String methodName = methodNameAndDesc.substring(0, p);
member = findMethod(realClass, methodName, memberDesc);
}
}
public RealMethodOrConstructor(@Nonnull Class<?> realClass, @Nonnull String methodName, @Nonnull String memberDesc)
throws NoSuchMethodException
{
if (methodName.charAt(0) == '<') {
member = findConstructor(realClass, memberDesc);
}
else {
member = findMethod(realClass, methodName, memberDesc);
}
}
@Nonnull
private static Constructor<?> findConstructor(@Nonnull Class<?> realClass, @Nonnull String methodDesc)
{
Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(methodDesc);
return ConstructorReflection.findSpecifiedConstructor(realClass, parameterTypes);
}
@Nonnull
private static Method findMethod(@Nonnull Class<?> realClass, @Nonnull String methodName, @Nonnull String methodDesc)
throws NoSuchMethodException
{
Class<?>[] parameterTypes = TypeDescriptor.getParameterTypes(methodDesc);
Class<?> ownerClass = realClass;
while (true) {
try {
Method method = ownerClass.getDeclaredMethod(methodName, parameterTypes);
if (method.isBridge()) {
ownerClass = ownerClass.getSuperclass();
continue;
}
return method;
}
catch (NoSuchMethodException e) {
Method interfaceMethod = findInterfaceMethod(ownerClass, methodName, parameterTypes);
if (interfaceMethod != null) {
return interfaceMethod;
}
ownerClass = ownerClass.getSuperclass();
if (ownerClass == Object.class) {
throw e;
}
}
}
}
@Nullable
private static Method findInterfaceMethod(
@Nonnull Class<?> aType, @Nonnull String methodName, @Nonnull Class<?>[] parameterTypes)
{
for (Class<?> anInterface : aType.getInterfaces()) {
try { return anInterface.getMethod(methodName, parameterTypes); } catch (NoSuchMethodException ignore) {}
}
return null;
}
@Nonnull
public <M extends Member> M getMember()
{
//noinspection unchecked
return (M) member;
}
}