From 453908cd4661add33ff2b553b946f8316cbf424f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Mon, 11 Jan 2021 11:25:45 +0800 Subject: [PATCH 1/3] add NoVerify class for accessing private member of any object --- .../core/accessor/PrivateAccessor.java | 78 +++++++++++++++---- .../exception/MemberNotExistException.java | 16 ++++ 2 files changed, 81 insertions(+), 13 deletions(-) create mode 100644 testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java diff --git a/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java b/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java index d95e60e..34e324a 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java @@ -1,5 +1,6 @@ package com.alibaba.testable.core.accessor; +import com.alibaba.testable.core.exception.MemberNotExistException; import com.alibaba.testable.core.util.TypeUtil; import java.lang.reflect.Field; @@ -12,14 +13,67 @@ public class PrivateAccessor { private static final String KOTLIN_COMPANION_FIELD = "Companion"; + public static class NoVerify { + public static T get(Object ref, String field) { + try { + return PrivateAccessor.get(ref, field); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + return null; + } + } + + public static void set(Object ref, String field, T value) { + try { + PrivateAccessor.set(ref, field, value); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + } + } + + public static T invoke(Object ref, String method, Object... args) { + try { + return PrivateAccessor.invoke(ref, method, args); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + return null; + } + } + + public static T getStatic(Class clazz, String field) { + try { + return PrivateAccessor.getStatic(clazz, field); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + return null; + } + } + + public static void setStatic(Class clazz, String field, T value) { + try { + PrivateAccessor.setStatic(clazz, field, value); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + } + } + + public static T invokeStatic(Class clazz, String method, Object... args) { + try { + return PrivateAccessor.invokeStatic(clazz, method, args); + } catch (MemberNotExistException e) { + System.err.println(e.toString()); + return null; + } + } + } + public static T get(Object ref, String field) { try { Field declaredField = ref.getClass().getDeclaredField(field); declaredField.setAccessible(true); return (T)declaredField.get(ref); } catch (Exception e) { - System.err.println("Failed to get private field \"" + field + "\": " + e.toString()); - return null; + throw new MemberNotExistException("Failed to get private field \"" + field + "\"", e); } } @@ -29,23 +83,23 @@ public class PrivateAccessor { declaredField.setAccessible(true); declaredField.set(ref, value); } catch (Exception e) { - System.err.println("Failed to set private field \"" + field + "\": " + e.toString()); + throw new MemberNotExistException("Failed to set private field \"" + field + "\"", e); } } public static T invoke(Object ref, String method, Object... args) { try { Class[] cls = TypeUtil.getClassesFromObjects(args); - Method declaredMethod = TypeUtil.getMethodByNameAndParameterTypes(ref.getClass().getDeclaredMethods(), method, cls); + Method declaredMethod = TypeUtil.getMethodByNameAndParameterTypes(ref.getClass().getDeclaredMethods(), + method, cls); if (declaredMethod != null) { declaredMethod.setAccessible(true); return (T)declaredMethod.invoke(ref, args); } } catch (Exception e) { - System.err.println("Failed to invoke private method \"" + method + "\": " + e.toString()); - return null; + throw new MemberNotExistException("Failed to invoke private method \"" + method + "\"", e); } - return null; + throw new MemberNotExistException("Private method \"" + method + "\" not found"); } public static T getStatic(Class clazz, String field) { @@ -54,8 +108,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); return (T)declaredField.get(null); } catch (Exception e) { - System.err.println("Failed to get private static field \"" + field + "\": " + e.toString()); - return null; + throw new MemberNotExistException("Failed to get private static field \"" + field + "\"", e); } } @@ -65,7 +118,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); declaredField.set(null, value); } catch (Exception e) { - System.err.println("Failed to set private static field \"" + field + "\": " + e.toString()); + throw new MemberNotExistException("Failed to set private static field \"" + field + "\"", e); } } @@ -87,9 +140,8 @@ public class PrivateAccessor { return (T)declaredMethod.invoke(companionInstance, args); } } catch (Exception e) { - System.err.println("Failed to invoke private static method \"" + method + "\": " + e.toString()); - return null; + throw new MemberNotExistException("Failed to invoke private static method \"" + method + "\"", e); } - return null; + throw new MemberNotExistException("Private static method \"" + method + "\" not found"); } } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java b/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java new file mode 100644 index 0000000..b13a5ad --- /dev/null +++ b/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java @@ -0,0 +1,16 @@ +package com.alibaba.testable.core.exception; + +/** + * @author flin + */ +public class MemberNotExistException extends RuntimeException { + + public MemberNotExistException(String message) { + super(message); + } + + public MemberNotExistException(String message, Throwable cause) { + super(message, cause); + } + +} From f9be92e9d06e4cff0aec3563e05ae643f6fd22ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Thu, 21 Jan 2021 22:44:51 +0800 Subject: [PATCH 2/3] for InvocationTargetException, bring root cause out --- .../core/accessor/PrivateAccessor.java | 47 ++++++++++--------- .../core/exception/MemberAccessException.java | 26 ++++++++++ .../exception/MemberNotExistException.java | 16 ------- 3 files changed, 52 insertions(+), 37 deletions(-) create mode 100644 testable-core/src/main/java/com/alibaba/testable/core/exception/MemberAccessException.java delete mode 100644 testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java diff --git a/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java b/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java index 34e324a..af36b23 100644 --- a/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java +++ b/testable-core/src/main/java/com/alibaba/testable/core/accessor/PrivateAccessor.java @@ -1,6 +1,6 @@ package com.alibaba.testable.core.accessor; -import com.alibaba.testable.core.exception.MemberNotExistException; +import com.alibaba.testable.core.exception.MemberAccessException; import com.alibaba.testable.core.util.TypeUtil; import java.lang.reflect.Field; @@ -17,8 +17,8 @@ public class PrivateAccessor { public static T get(Object ref, String field) { try { return PrivateAccessor.get(ref, field); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); return null; } } @@ -26,16 +26,16 @@ public class PrivateAccessor { public static void set(Object ref, String field, T value) { try { PrivateAccessor.set(ref, field, value); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); } } public static T invoke(Object ref, String method, Object... args) { try { return PrivateAccessor.invoke(ref, method, args); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); return null; } } @@ -43,8 +43,8 @@ public class PrivateAccessor { public static T getStatic(Class clazz, String field) { try { return PrivateAccessor.getStatic(clazz, field); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); return null; } } @@ -52,19 +52,24 @@ public class PrivateAccessor { public static void setStatic(Class clazz, String field, T value) { try { PrivateAccessor.setStatic(clazz, field, value); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); } } public static T invokeStatic(Class clazz, String method, Object... args) { try { return PrivateAccessor.invokeStatic(clazz, method, args); - } catch (MemberNotExistException e) { - System.err.println(e.toString()); + } catch (MemberAccessException e) { + printError(e); return null; } } + + private static void printError(MemberAccessException e) { + Throwable cause = e.getCause() == null ? e : e.getCause(); + System.err.println(cause.toString()); + } } public static T get(Object ref, String field) { @@ -73,7 +78,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); return (T)declaredField.get(ref); } catch (Exception e) { - throw new MemberNotExistException("Failed to get private field \"" + field + "\"", e); + throw new MemberAccessException("Failed to get private field \"" + field + "\"", e); } } @@ -83,7 +88,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); declaredField.set(ref, value); } catch (Exception e) { - throw new MemberNotExistException("Failed to set private field \"" + field + "\"", e); + throw new MemberAccessException("Failed to set private field \"" + field + "\"", e); } } @@ -97,9 +102,9 @@ public class PrivateAccessor { return (T)declaredMethod.invoke(ref, args); } } catch (Exception e) { - throw new MemberNotExistException("Failed to invoke private method \"" + method + "\"", e); + throw new MemberAccessException("Failed to invoke private method \"" + method + "\"", e); } - throw new MemberNotExistException("Private method \"" + method + "\" not found"); + throw new MemberAccessException("Private method \"" + method + "\" not found"); } public static T getStatic(Class clazz, String field) { @@ -108,7 +113,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); return (T)declaredField.get(null); } catch (Exception e) { - throw new MemberNotExistException("Failed to get private static field \"" + field + "\"", e); + throw new MemberAccessException("Failed to get private static field \"" + field + "\"", e); } } @@ -118,7 +123,7 @@ public class PrivateAccessor { declaredField.setAccessible(true); declaredField.set(null, value); } catch (Exception e) { - throw new MemberNotExistException("Failed to set private static field \"" + field + "\"", e); + throw new MemberAccessException("Failed to set private static field \"" + field + "\"", e); } } @@ -140,8 +145,8 @@ public class PrivateAccessor { return (T)declaredMethod.invoke(companionInstance, args); } } catch (Exception e) { - throw new MemberNotExistException("Failed to invoke private static method \"" + method + "\"", e); + throw new MemberAccessException("Failed to invoke private static method \"" + method + "\"", e); } - throw new MemberNotExistException("Private static method \"" + method + "\" not found"); + throw new MemberAccessException("Private static method \"" + method + "\" not found"); } } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberAccessException.java b/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberAccessException.java new file mode 100644 index 0000000..4ad56ce --- /dev/null +++ b/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberAccessException.java @@ -0,0 +1,26 @@ +package com.alibaba.testable.core.exception; + +import java.lang.reflect.InvocationTargetException; + +/** + * @author flin + */ +public class MemberAccessException extends RuntimeException { + + public MemberAccessException(String message) { + super(message); + } + + public MemberAccessException(String message, Throwable cause) { + super(message, getRootCause(cause)); + } + + private static Throwable getRootCause(Throwable cause) { + if (cause instanceof InvocationTargetException) { + return ((InvocationTargetException)cause).getTargetException(); + } else { + return cause; + } + } + +} diff --git a/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java b/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java deleted file mode 100644 index b13a5ad..0000000 --- a/testable-core/src/main/java/com/alibaba/testable/core/exception/MemberNotExistException.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.alibaba.testable.core.exception; - -/** - * @author flin - */ -public class MemberNotExistException extends RuntimeException { - - public MemberNotExistException(String message) { - super(message); - } - - public MemberNotExistException(String message, Throwable cause) { - super(message, cause); - } - -} From 650b385785f5f68973487707961738714a9e9752 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=88=9F?= Date: Sun, 24 Jan 2021 16:32:05 +0800 Subject: [PATCH 3/3] remove TestableMock annotation --- .../testable/agent/constant/ConstPool.java | 1 - .../agent/handler/TestClassHandler.java | 1 - .../transformer/TestableClassTransformer.java | 4 +--- .../core/annotation/TestableMock.java | 23 ------------------- 4 files changed, 1 insertion(+), 28 deletions(-) delete mode 100644 testable-core/src/main/java/com/alibaba/testable/core/annotation/TestableMock.java diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java index e23feb5..27116b9 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/constant/ConstPool.java @@ -16,7 +16,6 @@ public class ConstPool { public static final String MOCK_WITH = "com.alibaba.testable.core.annotation.MockWith"; public static final String MOCK_METHOD = "com.alibaba.testable.core.annotation.MockMethod"; public static final String MOCK_CONSTRUCTOR = "com.alibaba.testable.core.annotation.MockConstructor"; - public static final String TESTABLE_MOCK = "com.alibaba.testable.core.annotation.TestableMock"; public static final String CGLIB_CLASS_INFIX = "$$EnhancerBy"; diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java index fe55d11..3fb16c3 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/handler/TestClassHandler.java @@ -119,7 +119,6 @@ public class TestClassHandler extends BaseClassHandler { } for (AnnotationNode an : mn.visibleAnnotations) { if (ClassUtil.toByteCodeClassName(ConstPool.MOCK_METHOD).equals(an.desc) || - ClassUtil.toByteCodeClassName(ConstPool.TESTABLE_MOCK).equals(an.desc) || ClassUtil.toByteCodeClassName(ConstPool.MOCK_CONSTRUCTOR).equals(an.desc)) { return true; } diff --git a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java index e74a2e7..49c8a80 100644 --- a/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java +++ b/testable-agent/src/main/java/com/alibaba/testable/agent/transformer/TestableClassTransformer.java @@ -141,8 +141,7 @@ public class TestableClassTransformer implements ClassFileTransformer { String fullClassName = toDotSeparateFullClassName(an.desc); if (fullClassName.equals(ConstPool.MOCK_CONSTRUCTOR)) { addMockConstructor(methodInfos, cn, mn); - } else if (fullClassName.equals(ConstPool.MOCK_METHOD) || - fullClassName.equals(ConstPool.TESTABLE_MOCK)) { + } else if (fullClassName.equals(ConstPool.MOCK_METHOD)) { String targetMethod = AnnotationUtil.getAnnotationParameter( an, ConstPool.FIELD_TARGET_METHOD, mn.name, String.class); if (ConstPool.CONSTRUCTOR.equals(targetMethod)) { @@ -201,7 +200,6 @@ public class TestableClassTransformer implements ClassFileTransformer { for (AnnotationNode an : mn.visibleAnnotations) { String fullClassName = toDotSeparateFullClassName(an.desc); if (fullClassName.equals(ConstPool.MOCK_METHOD) || - fullClassName.equals(ConstPool.TESTABLE_MOCK) || fullClassName.equals(ConstPool.MOCK_CONSTRUCTOR)) { return true; } diff --git a/testable-core/src/main/java/com/alibaba/testable/core/annotation/TestableMock.java b/testable-core/src/main/java/com/alibaba/testable/core/annotation/TestableMock.java deleted file mode 100644 index 6d4ff70..0000000 --- a/testable-core/src/main/java/com/alibaba/testable/core/annotation/TestableMock.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.alibaba.testable.core.annotation; - -import java.lang.annotation.*; - -/** - * Mark method as mock method - * @deprecated will be remove in v0.5.0, use @MockMethod or @MockConstructor instead - * - * @author flin - */ -@Retention(RetentionPolicy.RUNTIME) -@Target(ElementType.METHOD) -@Documented -@Deprecated -public @interface TestableMock { - - /** - * mock specified method instead of method with same name - * @return target method name - */ - String targetMethod() default ""; - -}