no need to generate e.java any more

This commit is contained in:
金戟 2020-07-20 22:45:01 +08:00
parent bc62af8bb1
commit 0f007c6d96
7 changed files with 226 additions and 227 deletions

View File

@ -1,5 +1,7 @@
package com.alibaba.testable.accessor;
import com.alibaba.testable.util.TypeUtil;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
@ -31,11 +33,8 @@ public class PrivateAccessor {
public static <T> T invoke(Object ref, String method, Object... args) {
try {
Class[] cls = new Class[args.length];
for (int i = 0; i < args.length; i++) {
cls[i] = args[i].getClass();
}
Method declaredMethod = ref.getClass().getDeclaredMethod(method, cls);
Class[] cls = TypeUtil.gcs(args);
Method declaredMethod = TypeUtil.gm(ref.getClass().getDeclaredMethods(), method, cls);
declaredMethod.setAccessible(true);
return (T)declaredMethod.invoke(ref, args);
} catch (Exception e) {

View File

@ -3,7 +3,6 @@ package com.alibaba.testable.processor;
import com.alibaba.testable.annotation.EnableTestableInject;
import com.alibaba.testable.translator.EnableTestableInjectTranslator;
import com.alibaba.testable.translator.MethodRecordTranslator;
import com.alibaba.testable.util.ConstPool;
import com.alibaba.testable.util.ResourceUtil;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.tree.JCTree;
@ -15,11 +14,9 @@ import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.FileObject;
import javax.tools.JavaFileObject;
import javax.tools.StandardLocation;
import java.io.IOException;
import java.io.OutputStream;
import java.io.Writer;
import java.util.Set;
/**
@ -29,11 +26,9 @@ import java.util.Set;
@SupportedSourceVersion(SourceVersion.RELEASE_7)
public class EnableTestableInjectProcessor extends BaseProcessor {
private static final String JAVA_POSTFIX = ".java";
private static final String AGENT_TARGET_FOLDER = "generated_testable";
private static final String AGENT_TARGET_FILE = "agent.jar";
private static final String AGENT_TARGET_FOLDER = "";
private static final String AGENT_TARGET_FILE = "testable.jar";
private static final String AGENT_SOURCE_FILE = "testable-agent.jar";
private static final String NE_SOURCE_FILE = ConstPool.NE_CLS + JAVA_POSTFIX;
private static boolean hasFirstClassCompiled = false;
@Override
@ -50,12 +45,11 @@ public class EnableTestableInjectProcessor extends BaseProcessor {
private void createStaticNewClass() {
if (!checkFirstClassCompiled()) {
try {
writeBinaryFile(AGENT_TARGET_FOLDER, AGENT_TARGET_FILE, ResourceUtil.fetchBinary(AGENT_SOURCE_FILE));
writeSourceFile(ConstPool.NE_PKG_CLS, ResourceUtil.fetchText(NE_SOURCE_FILE));
} catch (IOException e) {
e.printStackTrace();
byte[] bytes = ResourceUtil.fetchBinary(AGENT_SOURCE_FILE);
if (bytes.length == 0) {
cx.logger.error("Failed to generate testable agent jar");
}
writeBinaryFile(AGENT_TARGET_FOLDER, AGENT_TARGET_FILE, bytes);
}
}
@ -74,20 +68,17 @@ public class EnableTestableInjectProcessor extends BaseProcessor {
tree.accept(new EnableTestableInjectTranslator(cx, methodRecordTranslator.getMethods()));
}
private void writeSourceFile(String fullQualityTypeName, String content) throws IOException {
JavaFileObject jfo = cx.filter.createSourceFile(fullQualityTypeName);
Writer writer = jfo.openWriter();
writer.write(content);
writer.flush();
writer.close();
}
private void writeBinaryFile(String path, String fileName, byte[] content) throws IOException {
FileObject resource = cx.filter.createResource(StandardLocation.SOURCE_OUTPUT, path, fileName);
OutputStream out = resource.openOutputStream();
out.write(content);
out.flush();
out.close();
private void writeBinaryFile(String path, String fileName, byte[] content) {
try {
FileObject resource = cx.filter.createResource(StandardLocation.SOURCE_OUTPUT, path, fileName);
OutputStream out = resource.openOutputStream();
out.write(content);
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
cx.logger.error("Failed to write " + fileName);
}
}
}

View File

@ -5,7 +5,7 @@ package com.alibaba.testable.util;
*/
public final class ConstPool {
public static final String NE_PKG = "generated_testable.n";
public static final String NE_PKG = "testable_internal.n";
public static final String NE_CLS = "e";
public static final String NE_NEW = "w";
public static final String NE_FUN = "f";

View File

@ -29,6 +29,10 @@ public class ResourceUtil {
public static byte[] fetchBinary(String fileName) {
InputStream in = ResourceUtil.class.getResourceAsStream("/" + fileName);
if (in == null) {
System.err.println("Resource " + fileName + " not exist");
return new byte[] {};
}
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
final int bufLen = 4 * 1024;
byte[] buf = new byte[bufLen];
@ -40,7 +44,7 @@ public class ResourceUtil {
buffer.close();
return buffer.toByteArray();
} catch (IOException e) {
System.err.println("Failed to fetch text file: " + fileName);
System.err.println("Failed to fetch file: " + fileName);
return new byte[] {};
}
}

View File

@ -0,0 +1,74 @@
package com.alibaba.testable.util;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
public class TypeUtil {
/**
* get classes of parameter objects
*/
public static Class[] gcs(Object[] as) {
Class[] cs = new Class[as.length];
for (int i = 0; i < cs.length; i++) {
cs[i] = as[i].getClass();
}
return cs;
}
/**
* get method by name and parameter matching
*/
public static Method gm(Method[] mds, String mn, Class[] cs) {
for (Method m : mds) {
if (m.getName().equals(mn) && te(m.getParameterTypes(), cs)) {
return m;
}
}
return null;
}
/**
* get constructor by parameter matching
*/
public static Constructor gc(Constructor<?>[] cons, Class[] cs) {
for (Constructor c : cons) {
if (te(c.getParameterTypes(), cs)) {
return c;
}
}
return null;
}
/**
* type equeals
*/
public static boolean te(Class[] c1, Class[] c2) {
if (c1.length != c2.length) {
return false;
}
for (int i = 0; i < c1.length; i++) {
if (!c1[i].equals(c2[i]) && !fe(c1[i], c2[i])) {
return false;
}
}
return true;
}
/**
* fuzzy equal
* @param c1 fact types (can be primary type)
* @param c2 user types
*/
private static boolean fe(Class c1, Class c2) {
return (c1.equals(int.class) && c2.equals(Integer.class)) ||
(c1.equals(long.class) && c2.equals(Long.class)) ||
(c1.equals(short.class) && c2.equals(Short.class)) ||
(c1.equals(boolean.class) && c2.equals(Boolean.class)) ||
(c1.equals(char.class) && c2.equals(Character.class)) ||
(c1.equals(byte.class) && c2.equals(Byte.class)) ||
(c1.equals(float.class) && c2.equals(Float.class)) ||
(c1.equals(double.class) && c2.equals(Double.class));
}
}

View File

@ -0,0 +1,125 @@
package testable_internal.n;
import com.alibaba.testable.util.TypeUtil;
import java.lang.Class;
import java.lang.Object;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
public final class e {
public static class p {
public Class c; // target instance type to new / method return type
public Class[] a; // constructor parameter types / member method parameter types
public Object o; // object which provides substitution / object which provides substitution
public String m; // substitutional method name / original member method name
public p(Class c, String m, Class[] a, Object o) {
this.c = c;
this.m = m;
this.a = a;
this.o = o;
}
}
private static List<p> pw = new ArrayList<>();
private static List<p> pf = new ArrayList<>();
/**
* add item to constructor pool
*/
public static void aw(p np) {
pw.add(np);
}
/**
* add item to method pool
*/
public static void af(p np) {
pf.add(np);
}
/**
* substitution entry for new
*/
public static <T> T w(Class<T> ct, Object... as) {
Class[] cs = TypeUtil.gcs(as);
if (!pw.isEmpty()) {
try {
p pi = gpw(ct, cs);
if (pi != null) {
Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a);
m.setAccessible(true);
return (T)m.invoke(pi.o, as);
}
} catch (Exception e) {
return null;
}
}
try {
Constructor c = TypeUtil.gc(ct.getConstructors(), cs);
if (c != null) {
return (T)c.newInstance(as);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* substitution entry for member call
*/
public static <T> T f(Object obj, String mn, Object... as) {
Class[] cs = TypeUtil.gcs(as);
if (!pf.isEmpty()) {
try {
p pi = gpf(mn, cs);
if (pi != null) {
Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a);
m.setAccessible(true);
return (T)m.invoke(pi.o, as);
}
} catch (Exception e) {
return null;
}
}
try {
Method m = TypeUtil.gm(obj.getClass().getDeclaredMethods(), mn, cs);
if (m != null) {
m.setAccessible(true);
return (T)m.invoke(obj, as);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* get from method pool by key
*/
private static p gpf(String mn, Class[] cs) {
for (p f : pf) {
if (f.m.equals(mn) && TypeUtil.te(f.a, cs)) {
return f;
}
}
return null;
}
/**
* get from constructor pool by key
*/
private static p gpw(Class ct, Class[] cs) {
for (p w : pw) {
if (w.c.equals(ct) && TypeUtil.te(w.a, cs)) {
return w;
}
}
return null;
}
}

View File

@ -1,194 +0,0 @@
package generated_testable.n;
import com.sun.tools.javac.util.Pair;
import java.lang.Class;
import java.lang.Object;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.*;
public final class e {
public static class p {
public Class c; // target instance type to new / method return type
public Class[] a; // constructor parameter types / member method parameter types
public Object o; // object which provides substitution / object which provides substitution
public String m; // substitutional method name / original member method name
public p(Class c, String m, Class[] a, Object o) {
this.c = c;
this.m = m;
this.a = a;
this.o = o;
}
}
private static List<p> pw = new ArrayList<>();
private static List<p> pf = new ArrayList<>();
/**
* add item to contructor pool
*/
public static void aw(p np) {
pw.add(np);
}
/**
* add item to method pool
*/
public static void af(p np) {
pf.add(np);
}
/**
* subsitituion entry for new
*/
public static <T> T w(Class<T> ct, Object... as) {
Class[] cs = new Class[as.length];
for (int i = 0; i < cs.length; i++) {
cs[i] = as[i].getClass();
}
if (!pw.isEmpty()) {
try {
p pi = gpw(ct, cs);
if (pi != null) {
Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a);
m.setAccessible(true);
return (T)m.invoke(pi.o, as);
}
} catch (Exception e) {
return null;
}
}
try {
Constructor c = gc(ct.getConstructors(), cs);
if (c != null) {
return (T)c.newInstance(as);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* subsitituion entry for member call
*/
public static <T> T f(Object obj, String mn, Object... as) {
Class[] cs = gcs(as);
if (!pf.isEmpty()) {
try {
p pi = gpf(mn, cs);
if (pi != null) {
Method m = pi.o.getClass().getDeclaredMethod(pi.m, pi.a);
m.setAccessible(true);
return (T)m.invoke(pi.o, as);
}
} catch (Exception e) {
return null;
}
}
try {
Method m = gm(obj.getClass().getDeclaredMethods(), mn, cs);
if (m != null) {
m.setAccessible(true);
return (T)m.invoke(obj, as);
}
} catch (Exception e) {
return null;
}
return null;
}
/**
* get classes of parameter objects
*/
private static Class[] gcs(Object[] as) {
Class[] cs = new Class[as.length];
for (int i = 0; i < cs.length; i++) {
cs[i] = as[i].getClass();
}
return cs;
}
/**
* get method by name and parameter matching
*/
private static Method gm(Method[] mds, String mn, Class[] cs) {
for (Method m : mds) {
if (m.getName().equals(mn) && te(m.getParameterTypes(), cs)) {
return m;
}
}
return null;
}
/**
* get from method pool by key
*/
private static p gpf(String mn, Class[] cs) {
for (p f : pf) {
if (f.m.equals(mn) && te(f.a, cs)) {
return f;
}
}
return null;
}
/**
* get contructor by parameter matching
*/
private static Constructor gc(Constructor<?>[] cons, Class[] cs) {
for (Constructor c : cons) {
if (te(c.getParameterTypes(), cs)) {
return c;
}
}
return null;
}
/**
* get from contructor pool by key
*/
private static p gpw(Class ct, Class[] cs) {
for (p w : pw) {
if (w.c.equals(ct) && te(w.a, cs)) {
return w;
}
}
return null;
}
/**
* type equeals
*/
private static boolean te(Class[] c1, Class[] c2) {
if (c1.length != c2.length) {
return false;
}
for (int i = 0; i < c1.length; i++) {
if (!c1[i].equals(c2[i]) && !fe(c1[i], c2[i])) {
return false;
}
}
return true;
}
/**
* fuzzy equal
* @param c1 fact types (can be primary type)
* @param c2 user types
*/
private static boolean fe(Class c1, Class c2) {
return (c1.equals(int.class) && c2.equals(Integer.class)) ||
(c1.equals(long.class) && c2.equals(Long.class)) ||
(c1.equals(short.class) && c2.equals(Short.class)) ||
(c1.equals(boolean.class) && c2.equals(Boolean.class)) ||
(c1.equals(char.class) && c2.equals(Character.class)) ||
(c1.equals(byte.class) && c2.equals(Byte.class)) ||
(c1.equals(float.class) && c2.equals(Float.class)) ||
(c1.equals(double.class) && c2.equals(Double.class));
}
}