All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.test4j.mock.faking.util.ReflectUtility Maven / Gradle / Ivy
package org.test4j.mock.faking.util;
import org.test4j.mock.Invocation;
import org.test4j.mock.functions.ESupplier;
import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.test4j.mock.faking.util.AsmConstant.*;
import static org.test4j.mock.faking.util.ClassFile.notObjectOrProxy;
@SuppressWarnings({"unused", "unchecked", "rawtypes", "UnusedReturnValue"})
public class ReflectUtility {
public static final Pattern JAVA_LANG = Pattern.compile("java.lang.", Pattern.LITERAL);
private static Throwable exceptionToThrow;
/**
* 通过 new Instance()的反射调用, 绕过对受检异常的封装
*
* @throws Throwable Exception
*/
public ReflectUtility() throws Throwable {
if (exceptionToThrow != null) {
throw exceptionToThrow;
}
}
/**
* 抛出 checkedException 异常
* 通过 new Instance()的反射调用, 绕过对受检异常的封装
*
* @param e Throwable
* @return ignore
*/
public static synchronized T doThrow(Throwable e) {
if (e instanceof RuntimeException) {
throw (RuntimeException) e;
} else if (e instanceof Error) {
throw (Error) e;
}
exceptionToThrow = e;
try {
ReflectUtility.class.newInstance();
} catch (InstantiationException | IllegalAccessException ignore) {
}
return null;
}
/**
* 根据签名描述查找构造函数或方法
*
* @param theClass class
* @param methodName method name
* @param memberDesc method 签名
* @return ignore
*/
public static Executable findMethodByDesc(Class theClass, String methodName, String memberDesc) {
Class[] paramTypes = TypeUtility.getParameterTypes(memberDesc);
Class superClass = theClass;
if (TypeUtility.isConstructor(methodName)) {
for (Constructor declaredConstructor : superClass.getDeclaredConstructors()) {
Class[] declaredParameterTypes = declaredConstructor.getParameterTypes();
int firstRealParameter = indexOfFirstRealParameter(declaredParameterTypes, paramTypes);
if (firstRealParameter == -1) {
continue;
}
if (acceptsArgumentTypes(declaredParameterTypes, paramTypes, firstRealParameter)) {
return declaredConstructor;
}
}
throw new IllegalArgumentException("Specified constructor not found: " + toDescriptionMethod(theClass.getSimpleName(), paramTypes));
} else {
while (notObjectOrProxy(superClass)) {
Method method = findMethodInClassOrInterface(superClass, methodName, paramTypes);
if (method == null) {
superClass = superClass.getSuperclass();
} else {
return method;
}
}
throw new RuntimeException("NoSuchMethod:" + theClass.getName() + "#" + methodName + memberDesc);
}
}
private static Method findMethodInClassOrInterface(Class theClass, String methodName, Class[] paramTypes) {
try {
Method method = theClass.getDeclaredMethod(methodName, paramTypes);
return method.isBridge() ? null : method;
} catch (NoSuchMethodException e) {
for (Class anInterface : theClass.getInterfaces()) {
try {
return anInterface.getMethod(methodName, paramTypes);
} catch (NoSuchMethodException ignore) {
}
}
}
return null;
}
/**
* 方法+参数描述
*
* @param method 方法名称
* @param paramTypes 方法参数
* @return ignore
*/
public static String toDescriptionMethod(String method, Class[] paramTypes) {
return method + Stream.of(paramTypes)
.map(Class::getCanonicalName)
.map(name -> JAVA_LANG.matcher(name).replaceAll(""))
.collect(Collectors.joining(", ", "(", ")"));
}
/**
* 1: 第一个入参是Invocation, 排除掉后参数个数相等
* 0: 参数个数相等
* -1: 参数个数不等
*
* @param mockParameterTypes mock参数类型
* @param realParameterTypes 实际方法参数类型
* @return ignore
*/
private static int indexOfFirstRealParameter(Class[] mockParameterTypes, Class[] realParameterTypes) {
int extraParameters = mockParameterTypes.length - realParameterTypes.length;
if (extraParameters == 1) {
return mockParameterTypes[0] == Invocation.class ? 1 : -1;
} else {
return extraParameters != 0 ? -1 : 0;
}
}
/**
* 判断参数列表是否匹配
*
* @param declaredTypes @Mock 方法声明的参数列表
* @param specifiedTypes 真实调用的参数列表
* @param firstParameter @Mock方法第一个参数是Invocation: 1, else: 0;
* @return ignore
*/
private static boolean acceptsArgumentTypes(Class[] declaredTypes, Class[] specifiedTypes, int firstParameter) {
for (int index = firstParameter; index < declaredTypes.length; index++) {
Class declaredType = declaredTypes[index];
Class specifiedType = specifiedTypes[index - firstParameter];
if (!TypeUtility.isAssignable(declaredType, specifiedType)) {
return false;
}
}
return true;
}
/**
* @param aClass class
* @param argument 参数签名
* @param type
* @return ignore
*/
public static T newInstance(Class aClass, String argument) {
try {
if (argument == null) {
Constructor constructor = aClass.getDeclaredConstructor();
return invoke(constructor, constructor::newInstance);
} else {
Constructor constructor = aClass.getDeclaredConstructor(String.class);
return invoke(constructor, () -> constructor.newInstance(argument));
}
} catch (NoSuchMethodException e) {
return doThrow(e);
}
}
public static T invoke(Object targetInstance, Method method, Object... methodArgs) {
return invoke(method, () -> method.invoke(targetInstance, methodArgs));
}
public static T invoke(Executable method, ESupplier supplier) {
boolean accessible = method.isAccessible();
try {
method.setAccessible(true);
Object obj = supplier.get();
return (T) obj;
} catch (IllegalArgumentException e) {
StackTrace.filterStackTrace(e);
throw new IllegalArgumentException("Failure to invoke method: " + method, e);
} catch (InvocationTargetException e) {
return doThrow(e.getCause());
} catch (Throwable e) {
return doThrow(e);
} finally {
method.setAccessible(accessible);
}
}
/**
* 返回对应的mock method name
*
* @param name method name
* @return ignore
*/
public static String getCorrespondingFakeName(String name) {
if (Method_Init.equals(name)) {
return Method_$Init;
}
if (Method_CL_INIT.equals(name)) {
return Method_$CL_Init;
}
return name;
}
}