mirror of
https://github.com/alibaba/testable-mock.git
synced 2025-01-25 11:51:15 +08:00
no need to generate e.java any more
This commit is contained in:
parent
bc62af8bb1
commit
0f007c6d96
@ -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) {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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";
|
||||
|
@ -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[] {};
|
||||
}
|
||||
}
|
||||
|
74
core/src/main/java/com/alibaba/testable/util/TypeUtil.java
Normal file
74
core/src/main/java/com/alibaba/testable/util/TypeUtil.java
Normal 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));
|
||||
}
|
||||
|
||||
}
|
125
core/src/main/java/testable_internal/n/e.java
Normal file
125
core/src/main/java/testable_internal/n/e.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
@ -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));
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user