feat: support generate method with template types

This commit is contained in:
金戟 2022-10-09 20:31:13 +08:00
parent 038ae8dba0
commit b654a3cfaa
2 changed files with 43 additions and 10 deletions

View File

@ -5,7 +5,8 @@ import com.alibaba.testable.core.tool.OmniConstructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import static com.alibaba.testable.core.constant.ConstPool.DOLLAR;
import static com.alibaba.testable.core.constant.ConstPool.DOT;
@ -19,13 +20,32 @@ public class ConstructionUtil {
sourceCode.append("package ").append(clazz.getPackage().getName()).append(";\n")
.append("public class ").append(getSubclassName(clazz))
.append(clazz.isInterface() ? " implements " : " extends ")
.append(clazz.getName().replace(DOLLAR, DOT))
.append(getClassName(clazz))
.append(" {\n");
for (Method m : clazz.getMethods()) {
if (!Modifier.isStatic(m.getModifiers()) && !Modifier.isFinal(m.getModifiers())) {
sourceCode.append("\tpublic ").append(m.getReturnType().getName().replace(DOLLAR, DOT)).append(" ")
sourceCode.append("\tpublic ");
TypeVariable<Method>[] typeParameters = m.getTypeParameters();
if (typeParameters.length > 0) {
sourceCode.append("<");
for (int i = 0; i < typeParameters.length; i++) {
sourceCode.append(typeParameters[i].getName()).append(" extends ");
Type[] bounds = typeParameters[i].getBounds();
for (int j = 0; j < bounds.length; j++) {
sourceCode.append(getClassName(bounds[j]));
if (j < bounds.length - 1) {
sourceCode.append(" & ");
}
}
if (i < typeParameters.length - 1) {
sourceCode.append(", ");
}
}
sourceCode.append("> ");
}
sourceCode.append(getClassName(m.getGenericReturnType())).append(" ")
.append(m.getName()).append("(");
Class<?>[] parameters = m.getParameterTypes();
Type[] parameters = m.getGenericParameterTypes();
for (int i = 0; i < parameters.length; i++) {
sourceCode.append(getParameterName(parameters[i])).append(" p").append(i);
if (i < parameters.length - 1) {
@ -34,8 +54,9 @@ public class ConstructionUtil {
}
sourceCode.append(") {\n");
if (!m.getReturnType().equals(void.class)) {
sourceCode.append("\t\treturn ").append(OmniConstructor.class.getName().replace(DOLLAR, DOT)).append(".")
.append("newInstance(").append(m.getReturnType().getName().replace(DOLLAR, DOT)).append(".class);\n");
sourceCode.append("\t\treturn (").append(getClassName(m.getGenericReturnType())).append(") ")
.append(getClassName(OmniConstructor.class)).append(".")
.append("newInstance(").append(getClassName(m.getReturnType())).append(".class);\n");
}
sourceCode.append("\t}\n");
}
@ -45,6 +66,8 @@ public class ConstructionUtil {
try {
return (T) InMemoryJavaCompiler.newInstance()
.useParentClassLoader(clazz.getClassLoader())
.useOptions("-Xlint:unchecked")
.ignoreWarnings()
.compile(clazz.getPackage().getName() + DOT + getSubclassName(clazz), sourceCode.toString())
.newInstance();
} catch (Exception e) {
@ -52,11 +75,20 @@ public class ConstructionUtil {
}
}
private static String getParameterName(Class<?> parameter) {
if (parameter.isArray()) {
return getParameterName(parameter.getComponentType()) + "[]";
private static String getClassName(Type clazz) {
if (clazz instanceof Class) {
return ((Class<?>)clazz).getName().replace(DOLLAR, DOT);
} else if (clazz instanceof TypeVariable) {
return ((TypeVariable<?>)clazz).getName();
}
return parameter.getName().replace(DOLLAR, DOT);
return clazz.toString().replaceAll("@.*$", "").replaceAll("^.* ", "");
}
private static String getParameterName(Type parameter) {
if (parameter instanceof Class && ((Class<?>)parameter).isArray()) {
return getParameterName(((Class<?>)parameter).getComponentType()) + "[]";
}
return getClassName(parameter);
}
private static String getSubclassName(Class<?> clazz) {

View File

@ -13,6 +13,7 @@ class ConstructionUtilTest {
int func2(double d, boolean b);
String fun3(String s, byte[] b);
EmptyInterface fun4(RealInterface i);
<T> T fun5(T i);
}
public static abstract class AbstractClazz implements RealInterface {