diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..73610e73 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,17 @@ +language: generic + +jdk: + - openjdk6 + - oraclejdk6 + +cache: + directories: + - "$HOME/.m2/repository" + +script: + - cd bin + - ./sandbox-packages.sh + - cd .. + +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/README.md b/README.md index c2bfe735..5705b11e 100755 --- a/README.md +++ b/README.md @@ -1,4 +1,11 @@ ## ![BANNER](https://github.com/alibaba/jvm-sandbox/wiki/img/BANNER.png) + +[![Build Status](https://travis-ci.org/alibaba/jvm-sandbox.svg?branch=develop-for-20181027)](https://travis-ci.org/alibaba/jvm-sandbox) +[![codecov](https://codecov.io/gh/alibaba/jvm-sandbox/branch/develop-for-20181027/graph/badge.svg)](https://codecov.io/gh/alibaba/jvm-sandbox) +![license](https://img.shields.io/github/license/alibaba/arthas.svg) +[![Average time to resolve an issue](http://isitmaintained.com/badge/resolution/alibaba/jvm-sandbox.svg)](http://isitmaintained.com/project/alibaba/jvm-sandbox "Average time to resolve an issue") +[![Percentage of issues still open](http://isitmaintained.com/badge/open/alibaba/jvm-sandbox.svg)](http://isitmaintained.com/project/alibaba/jvm-sandbox "Percentage of issues still open") + > JVM沙箱容器,一种JVM的非侵入式运行期AOP解决方案
> Real - time non-invasive AOP framework container based on JVM diff --git a/bin/sandbox-packages.sh b/bin/sandbox-packages.sh index fcd9205f..92ee26cf 100755 --- a/bin/sandbox-packages.sh +++ b/bin/sandbox-packages.sh @@ -14,7 +14,7 @@ exit_on_err() } # maven package the sandbox -mvn clean package -Dmaven.test.skip=false -f ../pom.xml \ +mvn clean cobertura:cobertura package -Dmaven.test.skip=false -f ../pom.xml \ || exit_on_err 1 "package sandbox failed." # reset the target dir diff --git a/pom.xml b/pom.xml index 459f02e9..bbaddbe5 100644 --- a/pom.xml +++ b/pom.xml @@ -4,14 +4,14 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT pom sandbox ${sandbox.version} UTF-8 - 1.1.0 + 1.1.1-SNAPSHOT diff --git a/sandbox-agent/pom.xml b/sandbox-agent/pom.xml index 5b1519db..c40e5b6e 100755 --- a/sandbox-agent/pom.xml +++ b/sandbox-agent/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-agent sandbox-agent ${sandbox.version} diff --git a/sandbox-api/pom.xml b/sandbox-api/pom.xml index 63f7abc7..d5b869fc 100755 --- a/sandbox-api/pom.xml +++ b/sandbox-api/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-api sandbox-api ${sandbox.version} diff --git a/sandbox-common-api/pom.xml b/sandbox-common-api/pom.xml index 8e476bd4..13b7e8ac 100644 --- a/sandbox-common-api/pom.xml +++ b/sandbox-common-api/pom.xml @@ -6,7 +6,7 @@ sandbox com.alibaba.jvm.sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-common-api sandbox-common-api ${sandbox.version} diff --git a/sandbox-core/pom.xml b/sandbox-core/pom.xml index 550b3b1e..1eb69a21 100755 --- a/sandbox-core/pom.xml +++ b/sandbox-core/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-core sandbox-core ${sandbox.version} @@ -134,17 +134,17 @@ org.ow2.asm asm - 6.0 + 7.0 org.ow2.asm asm-commons - 6.0 + 7.0 org.ow2.asm asm-util - 6.0 + 7.0 org.apache.commons diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java index e68283f2..b035cc16 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/EventEnhancer.java @@ -17,6 +17,7 @@ import static org.objectweb.asm.ClassReader.EXPAND_FRAMES; import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; import static org.objectweb.asm.ClassWriter.COMPUTE_MAXS; +import static org.objectweb.asm.Opcodes.ASM7; /** * 事件代码增强器 @@ -90,7 +91,7 @@ private byte[] weavingEvent(final ClassLoader targetClassLoader, final int targetClassLoaderObjectID = ObjectIDs.instance.identity(targetClassLoader); cr.accept( new EventWeaver( - Opcodes.ASM6, cw, namespace, listenerId, + ASM7, cw, namespace, listenerId, targetClassLoaderObjectID, cr.getClassName(), signCodes, diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/ReWriteMethod.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/ReWriteMethod.java index 3e73fee2..211911a6 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/ReWriteMethod.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/enhance/weaver/asm/ReWriteMethod.java @@ -18,7 +18,7 @@ public class ReWriteMethod extends AdviceAdapter implements Opcodes, AsmTypes, A * Creates a new {@link AdviceAdapter}. * * @param api the ASM API version implemented by this visitor. Must be one - * of {@link Opcodes#ASM4} or {@link Opcodes#ASM6}. + * of {@link Opcodes#ASM4} or {@link Opcodes#ASM7}. * @param mv the method visitor to which this adapter delegates calls. * @param access the method's access flags (see {@link Opcodes}). * @param name the method's name. diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java index 4acb9e38..14f5b705 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/server/jetty/JettyCoreServer.java @@ -69,6 +69,7 @@ public boolean isBind() { @Override public void unbind() throws IOException { try { + initializer.destroyProcess(new Initializer.Processor() { @Override public void process() throws Throwable { @@ -86,6 +87,10 @@ public void process() throws Throwable { httpServer.destroy(); logger.info("{} was destroyed.", this); + // 关闭对象池 + EventListenerHandlers.getSingleton().getEventPool().close(); + logger.info("{} was closed the Event-Pool!", this); + } catch (Throwable cause) { logger.warn("{} unBind failed.", this, cause); throw new IOException("unBind failed.", cause); diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/EventPool.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/EventPool.java index 54b17838..9fc39551 100755 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/EventPool.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/EventPool.java @@ -28,6 +28,18 @@ public EventPool() { this.isEnable = this.pool != null; } + /** + * 关闭并清理对象池 + *

+ * 修复问题:#108 + *

+ */ + public void close() { + if (null != pool) { + pool.close(); + } + } + private KeyedObjectPool createEventPool() { final CoreConfigure cfg = CoreConfigure.getInstance(); if (cfg.isEventPoolEnable()) { diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/BehaviorStructure.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/BehaviorStructure.java index 954ae250..2048ef06 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/BehaviorStructure.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/BehaviorStructure.java @@ -28,29 +28,6 @@ public class BehaviorStructure extends MemberStructure { private final List exceptionTypeClassStructures; private final List annotationTypeClassStructures; - private final LazyGet signCodeLazyGet = new LazyGet() { - @Override - protected String initialValue() { - return String.format("%s#%s(%s)", - getDeclaringClassStructure().getJavaClassName(), - getName(), - join(takeJavaClassNames(getParameterTypeClassStructures()), ",") - ); - } - }; - - private final LazyGet toStringLazyGet = new LazyGet() { - @Override - protected String initialValue() { - return String.format("%s:[%s]:%s:%s", - getReturnTypeClassStructure().getJavaClassName(), - join(takeJavaClassNames(getAnnotationTypeClassStructures()), ","), - getSignCode(), - join(takeJavaClassNames(getExceptionTypeClassStructures()), ",") - ); - } - }; - BehaviorStructure(final Access access, final String name, final ClassStructure declaringClassStructure, @@ -109,6 +86,18 @@ private Collection takeJavaClassNames(final Collection c return javaClassNames; } + + private final LazyGet signCodeLazyGet = new LazyGet() { + @Override + protected String initialValue() { + return String.format("%s#%s(%s)", + getDeclaringClassStructure().getJavaClassName(), + getName(), + join(takeJavaClassNames(getParameterTypeClassStructures()), ",") + ); + } + }; + /** * 获取行为签名 *

@@ -121,6 +110,18 @@ public String getSignCode() { return signCodeLazyGet.get(); } + private final LazyGet toStringLazyGet = new LazyGet() { + @Override + protected String initialValue() { + return String.format("%s:[%s]:%s:%s", + getReturnTypeClassStructure().getJavaClassName(), + join(takeJavaClassNames(getAnnotationTypeClassStructures()), ","), + getSignCode(), + join(takeJavaClassNames(getExceptionTypeClassStructures()), ",") + ); + } + }; + @Override public String toString() { // %s[0] : return-type diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java index 8ca59287..16e24508 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByAsm.java @@ -6,6 +6,7 @@ import com.alibaba.jvm.sandbox.core.util.collection.Pair; import com.alibaba.jvm.sandbox.core.util.matcher.structure.PrimitiveClassStructure.Primitive; import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; import org.objectweb.asm.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -13,6 +14,7 @@ import java.io.IOException; import java.io.InputStream; import java.util.*; +import java.util.concurrent.atomic.AtomicInteger; import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName; import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toJavaClassName; @@ -27,7 +29,7 @@ class AccessImplByAsm implements Access { private final int access; - AccessImplByAsm(int access) { + AccessImplByAsm(final int access) { this.access = access; } @@ -61,7 +63,9 @@ public boolean isProtected() { @Override public boolean isStatic() { - return BitUtils.isIn(getAccess(), ACC_STATIC); + // 隐性的Java语法约束:如果是接口类型,就一定是静态的 + return isInterface() + || BitUtils.isIn(getAccess(), ACC_STATIC); } @Override @@ -165,23 +169,30 @@ class PrimitiveClassStructure extends EmptyClassStructure { } public enum Primitive { - BOOLEAN("boolean"), - CHAR("char"), - BYTE("byte"), - INT("int"), - SHORT("short"), - LONG("long"), - FLOAT("float"), - DOUBLE("double"), - VOID("void"); + BOOLEAN("boolean", boolean.class), + CHAR("char", char.class), + BYTE("byte", byte.class), + INT("int", int.class), + SHORT("short", short.class), + LONG("long", long.class), + FLOAT("float", float.class), + DOUBLE("double", double.class), + VOID("void", void.class); private final String type; + private final Access access; - Primitive(final String type) { + Primitive(final String type, final Class clazz) { this.type = type; + this.access = new AccessImplByJDKClass(clazz); } } + @Override + public Access getAccess() { + return primitive.access; + } + @Override public String getJavaClassName() { return primitive.type; @@ -208,10 +219,7 @@ class ArrayClassStructure extends EmptyClassStructure { @Override public String getJavaClassName() { - return new StringBuilder() - .append(elementClassStructure.getJavaClassName()) - .append("[]") - .toString(); + return elementClassStructure.getJavaClassName() + "[]"; } } @@ -227,16 +235,35 @@ public class ClassStructureImplByAsm extends FamilyClassStructure { private final ClassLoader loader; private final Access access; - public ClassStructureImplByAsm(final InputStream classInputStream, + ClassStructureImplByAsm(final InputStream classInputStream, final ClassLoader loader) throws IOException { this(IOUtils.toByteArray(classInputStream), loader); } - public ClassStructureImplByAsm(final byte[] classByteArray, + ClassStructureImplByAsm(final byte[] classByteArray, final ClassLoader loader) { this.classReader = new ClassReader(classByteArray); this.loader = loader; - this.access = new AccessImplByAsm(this.classReader.getAccess()); + this.access = fixAccess(); + } + + /** + * 修正内部类时候Access的获取策略差异 + * + * @return 修正后的Access + */ + private Access fixAccess() { + final AtomicInteger accessRef = new AtomicInteger(this.classReader.getAccess()); + final String internalClassName = this.classReader.getClassName(); + this.classReader.accept(new ClassVisitor(ASM7) { + @Override + public void visitInnerClass(String name, String outerName, String innerName, int access) { + if (StringUtils.equals(name, internalClassName)) { + accessRef.set(access); + } + } + }, ASM7); + return new AccessImplByAsm(accessRef.get()); } private boolean isBootstrapClassLoader() { @@ -283,6 +310,7 @@ private ClassStructure newInstance(final String javaClassName) { if (classStructureCache.containsKey(pair)) { return classStructureCache.get(pair); } else { + final InputStream is = getResourceAsStream(internalClassNameToResourceName(toInternalClassName(javaClassName))); if (null != is) { try { @@ -300,19 +328,6 @@ private ClassStructure newInstance(final String javaClassName) { } } -// // 是个普通Java类型 -// final InputStream is = getResourceAsStream(internalClassNameToResourceName(toInternalClassName(javaClassName))); -// if (null != is) { -// try { -// return new ClassStructureImplByAsm(is, loader); -// } catch (Throwable cause) { -// // ignore -// logger.warn("new instance class structure by using ASM failed, will return null. class={};loader={};", -// javaClassName, loader, cause); -// } finally { -// IOUtils.closeQuietly(is); -// } -// } // 出现异常或者找不到 return null; } @@ -350,8 +365,12 @@ public ClassLoader getClassLoader() { private final LazyGet superClassStructureLazyGet = new LazyGet() { @Override - protected ClassStructure initialValue() throws Throwable { - return newInstance(toJavaClassName(classReader.getSuperName())); + protected ClassStructure initialValue() { + final String superInternalClassName = classReader.getSuperName(); + if (StringUtils.equals("java/lang/Object", superInternalClassName)) { + return null; + } + return newInstance(toJavaClassName(superInternalClassName)); } }; @@ -363,7 +382,7 @@ public ClassStructure getSuperClassStructure() { private final LazyGet> interfaceClassStructuresLazyGet = new LazyGet>() { @Override - protected List initialValue() throws Throwable { + protected List initialValue() { return newInstances(classReader.getInterfaces()); } }; @@ -376,9 +395,9 @@ public List getInterfaceClassStructures() { private final LazyGet> annotationTypeClassStructuresLazyGet = new LazyGet>() { @Override - protected List initialValue() throws Throwable { + protected List initialValue() { final List annotationTypeClassStructures = new ArrayList(); - accept(new ClassVisitor(ASM6) { + accept(new ClassVisitor(ASM7) { @Override public AnnotationVisitor visitAnnotation(String desc, boolean visible) { @@ -405,9 +424,9 @@ public List getAnnotationTypeClassStructures() { private final LazyGet> behaviorStructuresLazyGet = new LazyGet>() { @Override - protected List initialValue() throws Throwable { + protected List initialValue() { final List behaviorStructures = new ArrayList(); - accept(new ClassVisitor(ASM6) { + accept(new ClassVisitor(ASM7) { @Override public MethodVisitor visitMethod(final int access, @@ -415,7 +434,14 @@ public MethodVisitor visitMethod(final int access, final String desc, final String signature, final String[] exceptions) { - return new MethodVisitor(ASM6, super.visitMethod(access, name, desc, signature, exceptions)) { + + // 修复ASM会把列入正常方法中的问题 + // 实际上这个方法并不会参与到任何的逻辑判断 + if (StringUtils.equals("", name)) { + return super.visitMethod(access, name, desc, signature, exceptions); + } + + return new MethodVisitor(ASM7, super.visitMethod(access, name, desc, signature, exceptions)) { private final Type methodType = Type.getMethodType(desc); private final List annotationTypeClassStructures = new ArrayList(); @@ -488,4 +514,10 @@ public Access getAccess() { return access; } + @Override + public String toString() { + return "ClassStructureImplByAsm{" + + "javaClassName='" + getJavaClassName() + '\'' + + '}'; + } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java index 7cded9d4..764676a5 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/ClassStructureImplByJDK.java @@ -8,6 +8,7 @@ import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; abstract class ModifierAccess implements Access { @@ -136,20 +137,19 @@ private List newInstances(final Class[] classArray) { @Override public String getJavaClassName() { - if (null != javaClassName) { - return javaClassName; - } - - return javaClassName = clazz.isArray() - ? clazz.getCanonicalName() - : clazz.getName(); + return null != javaClassName + ? javaClassName + : (javaClassName = getJavaClassName(clazz)); + } -// final String canonicalName = clazz.getCanonicalName(); -// return javaClassName = StringUtils.isEmpty(canonicalName) -// ? clazz.getName() -// : canonicalName; + private String getJavaClassName(Class clazz) { + if (clazz.isArray()) { + return getJavaClassName(clazz.getComponentType()) + "[]"; + } + return clazz.getName(); } + @Override public ClassLoader getClassLoader() { return clazz.getClassLoader(); @@ -157,7 +157,10 @@ public ClassLoader getClassLoader() { @Override public ClassStructure getSuperClassStructure() { - return newInstance(clazz.getSuperclass()); + // 过滤掉Object.class + return Object.class.equals(clazz.getSuperclass()) + ? null + : newInstance(clazz.getSuperclass()); } @Override @@ -183,8 +186,8 @@ private Class[] getAnnotationTypeArray(final Annotation[] annotationArray) { private final LazyGet> annotationTypeClassStructuresLazyGet = new LazyGet>() { @Override - protected List initialValue() throws Throwable { - return newInstances(getAnnotationTypeArray(clazz.getDeclaredAnnotations())); + protected List initialValue() { + return Collections.unmodifiableList(newInstances(getAnnotationTypeArray(clazz.getDeclaredAnnotations()))); } }; @@ -228,7 +231,7 @@ protected List initialValue() { for (final Method method : clazz.getDeclaredMethods()) { behaviorStructures.add(newBehaviorStructure(method)); } - return behaviorStructures; + return Collections.unmodifiableList(behaviorStructures); } }; @@ -242,5 +245,8 @@ public Access getAccess() { return new AccessImplByJDKClass(clazz); } - + @Override + public String toString() { + return "ClassStructureImplByJDK{" + "javaClassName='" + javaClassName + '\'' + '}'; + } } diff --git a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/FamilyClassStructure.java b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/FamilyClassStructure.java index f269eedc..a639d815 100644 --- a/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/FamilyClassStructure.java +++ b/sandbox-core/src/main/java/com/alibaba/jvm/sandbox/core/util/matcher/structure/FamilyClassStructure.java @@ -4,7 +4,6 @@ import java.lang.annotation.Inherited; import java.util.HashSet; -import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; @@ -13,7 +12,7 @@ public abstract class FamilyClassStructure implements ClassStructure { private final LazyGet> familyInterfaceClassStructuresLazyGet = new LazyGet>() { @Override - protected Set initialValue() throws Throwable { + protected Set initialValue() { final Set familyInterfaceClassStructures = new HashSet(); for (final ClassStructure interfaceClassStructure : getInterfaceClassStructures()) { // 1. 先加自己声明的接口 @@ -21,6 +20,13 @@ protected Set initialValue() throws Throwable { // 2. 再加接口所声明的祖先(接口继承) familyInterfaceClassStructures.addAll(interfaceClassStructure.getFamilyInterfaceClassStructures()); } + + // BUGFIX: 修复获取家族接口类结构时忘记考虑自身父类的情况 + // AUTHOR: oldmanpushcart@gmail.com + for (final ClassStructure superClassStructure : getFamilySuperClassStructures()) { + familyInterfaceClassStructures.addAll(superClassStructure.getFamilyInterfaceClassStructures()); + } + return familyInterfaceClassStructures; } }; @@ -34,7 +40,7 @@ public Set getFamilyInterfaceClassStructures() { private final LazyGet> familyTypeClassStructuresLazyGet = new LazyGet>() { @Override - protected Set initialValue() throws Throwable { + protected Set initialValue() { final Set familyClassStructures = new LinkedHashSet(); // 注入家族类&家族类所声明的家族接口 @@ -71,25 +77,24 @@ private static boolean isInheritedAnnotationType(ClassStructure classStructure) } // 过滤掉没有@Inherited标注的Annotation,因为他们不能继承 - private Set filterInheritedAnnotationTypeClassStructure(final Set classStructures) { - final Iterator itCs = new HashSet(classStructures).iterator(); - while (itCs.hasNext()) { - final ClassStructure annotationTypeClassStructure = itCs.next(); - if (!isInheritedAnnotationType(annotationTypeClassStructure)) { - itCs.remove(); + private Set newSetWithFilterInheritedAnnotationTypeClassStructure(final Set classStructures) { + final Set inheritedAnnotationSet = new LinkedHashSet(); + for (final ClassStructure classStructure : classStructures) { + if (isInheritedAnnotationType(classStructure)) { + inheritedAnnotationSet.add(classStructure); } } - return classStructures; + return inheritedAnnotationSet; } private final LazyGet> familyAnnotationTypeClassStructuresLazyGet = new LazyGet>() { @Override - protected Set initialValue() throws Throwable { + protected Set initialValue() { final Set familyAnnotationTypeClassStructures = new HashSet(getAnnotationTypeClassStructures()); for (final ClassStructure familyClassStructure : getFamilyTypeClassStructures()) { familyAnnotationTypeClassStructures.addAll( - filterInheritedAnnotationTypeClassStructure( + newSetWithFilterInheritedAnnotationTypeClassStructure( familyClassStructure.getFamilyAnnotationTypeClassStructures() ) );//addAll @@ -106,7 +111,7 @@ public Set getFamilyAnnotationTypeClassStructures() { private final LazyGet> familySuperClassStructuresLazyGet = new LazyGet>() { @Override - protected LinkedHashSet initialValue() throws Throwable { + protected LinkedHashSet initialValue() { final LinkedHashSet familySuperClassStructures = new LinkedHashSet(); final ClassStructure superClassStructure = getSuperClassStructure(); if (null != superClassStructure) { diff --git a/sandbox-debug-module/pom.xml b/sandbox-debug-module/pom.xml index 6400d12f..50ab0631 100755 --- a/sandbox-debug-module/pom.xml +++ b/sandbox-debug-module/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox-module-starter - 1.1.0 + 1.1.1-SNAPSHOT ../sandbox-module-starter/pom.xml sandbox-debug-module diff --git a/sandbox-mgr-module/pom.xml b/sandbox-mgr-module/pom.xml index 0b90c283..5242785d 100755 --- a/sandbox-mgr-module/pom.xml +++ b/sandbox-mgr-module/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox-module-starter - 1.1.0 + 1.1.1-SNAPSHOT ../sandbox-module-starter/pom.xml sandbox-mgr-module diff --git a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java index 32f70180..32986785 100644 --- a/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java +++ b/sandbox-mgr-module/src/main/java/com/alibaba/jvm/sandbox/module/mgr/ControlModule.java @@ -7,15 +7,12 @@ import com.alibaba.jvm.sandbox.api.resource.ConfigInfo; import com.alibaba.jvm.sandbox.api.resource.ModuleManager; import org.apache.commons.lang3.StringUtils; -import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.commons.lang3.reflect.MethodUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.annotation.Resource; import javax.servlet.http.HttpServletResponse; -import java.io.IOException; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; diff --git a/sandbox-mgr-provider/pom.xml b/sandbox-mgr-provider/pom.xml index 0532825e..4f0160d7 100644 --- a/sandbox-mgr-provider/pom.xml +++ b/sandbox-mgr-provider/pom.xml @@ -6,7 +6,7 @@ sandbox com.alibaba.jvm.sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-mgr-provider sandbox-mgr-provider ${sandbox.version} diff --git a/sandbox-module-starter/pom.xml b/sandbox-module-starter/pom.xml index 4b163eb4..d9495278 100644 --- a/sandbox-module-starter/pom.xml +++ b/sandbox-module-starter/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-module-starter sandbox-module-starter ${sandbox.version} diff --git a/sandbox-provider-api/pom.xml b/sandbox-provider-api/pom.xml index f71ad633..ab9d1162 100644 --- a/sandbox-provider-api/pom.xml +++ b/sandbox-provider-api/pom.xml @@ -6,7 +6,7 @@ sandbox com.alibaba.jvm.sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-provider-api sandbox-provider-api ${sandbox.version} diff --git a/sandbox-qatest/pom.xml b/sandbox-qatest/pom.xml index 02ed5073..8501d40d 100644 --- a/sandbox-qatest/pom.xml +++ b/sandbox-qatest/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT com.alibaba.jvm.sandbox sandbox-qatest @@ -22,6 +22,18 @@ -Xbootclasspath/p:./lib/sandbox-spy-1.1.0-for-qatest.jar + + org.codehaus.mojo + cobertura-maven-plugin + 2.7 + + + html + xml + + + + diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/CoreEnhanceBaseTestCase.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/CoreEnhanceBaseTestCase.java index 824e1927..382a3f34 100644 --- a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/CoreEnhanceBaseTestCase.java +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/enhance/CoreEnhanceBaseTestCase.java @@ -10,7 +10,6 @@ import com.alibaba.jvm.sandbox.core.util.SandboxReflectUtils; import com.alibaba.jvm.sandbox.core.util.matcher.ExtFilterMatcher; import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureImplByJDK; -import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.StringUtils; import java.io.ByteArrayInputStream; @@ -21,54 +20,35 @@ import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; -import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName; +import static com.alibaba.jvm.sandbox.qatest.util.QaClassUtils.toByteArray; +import static com.alibaba.jvm.sandbox.qatest.util.QaClassUtils.toResourceName; public class CoreEnhanceBaseTestCase { private static final AtomicInteger LISTENER_ID_SEQ = new AtomicInteger(1000); - /** - * 目标Class文件转换为字节码数组 - * - * @param targetClass 目标Class文件 - * @return 目标Class文件字节码数组 - * @throws IOException 转换出错 - */ - protected byte[] toByteArray(final Class targetClass) throws IOException { - final InputStream is = targetClass.getClassLoader().getResourceAsStream(toResourceName(targetClass.getName())); - try { - return IOUtils.toByteArray(is); - } finally { - IOUtils.closeQuietly(is); - } - } - - private String toResourceName(String javaClassName) { - return toInternalClassName(javaClassName).concat(".class"); - } - private class TestClassLoader extends ClassLoader { private final Map javaClassByteArrayMap = new HashMap(); -// @Override -// protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { -// final Class loadedClass = findLoadedClass(name); -// if (loadedClass == null) { -// try { -// final Class aClass = findClass(name); -// if (resolve) { -// resolveClass(aClass); -// } -// return aClass; -// } catch (Exception e) { -// return super.loadClass(name, resolve); -// } -// } else { -// return loadedClass; -// } -// } + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + final Class loadedClass = findLoadedClass(name); + if (loadedClass == null) { + try { + final Class aClass = findClass(name); + if (resolve) { + resolveClass(aClass); + } + return aClass; + } catch (Exception e) { + return super.loadClass(name, resolve); + } + } else { + return loadedClass; + } + } public Class defineClass(final String javaClassName, final byte[] classByteArray) throws InvocationTargetException, IllegalAccessException { diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/ClassStructureTestCaseByChildClass.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/ClassStructureTestCaseByChildClass.java new file mode 100644 index 00000000..c58425ba --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/ClassStructureTestCaseByChildClass.java @@ -0,0 +1,361 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure; +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureFactory; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.BehaviorStructureAsserter; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.BehaviorStructureCollectionAsserter; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.ClassStructureAsserter; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.target.ChildClass; +import org.apache.commons.lang3.StringUtils; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import java.io.IOException; +import java.util.Collection; + +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.AccessAsserter.AccessIsEnum.*; +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.BehaviorStructureCollectionAsserter.buildBehaviorSignCodeArrayAsserter; +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.ClassStructureCollectionAsserter.buildEmptyJavaClassNameArrayAsserter; +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.ClassStructureCollectionAsserter.buildJavaClassNameArrayAsserter; +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.MappingAsserter.Mode.ALL; +import static com.alibaba.jvm.sandbox.qatest.util.QaClassUtils.toByteArray; +import static java.util.Arrays.asList; + +@RunWith(Parameterized.class) +public class ClassStructureTestCaseByChildClass { + + private static final String PACKAGE_PREFIX = "com.alibaba.jvm.sandbox.qatest.core.util.matcher.target."; + + @Parameterized.Parameters + public static Collection getData() throws IOException { + return asList( + new Object[]{ClassStructureFactory.createClassStructure(ChildClass.class)}, + new Object[]{ClassStructureFactory.createClassStructure(toByteArray(ChildClass.class), ChildClass.class.getClassLoader())} + ); + } + + private final ClassStructure childClassStructure; + + public ClassStructureTestCaseByChildClass(ClassStructure childClassStructure) { + this.childClassStructure = childClassStructure; + } + + + private static String buildSignCode(final String javaClassName, + final String name, + final String... parameterJavaClassName) { + return String.format( + "%s#%s(%s)", + javaClassName, + name, + StringUtils.join(parameterJavaClassName, ",") + ); + } + + @Test + public void test$$ChildClassStructure() { + + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass") + .assertAccess(IS_PUBLIC) + .assertSuper( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ParentClass") + .assertAccess(IS_PUBLIC, IS_ABSTRACT) + ) + .assertInterfaces(buildEmptyJavaClassNameArrayAsserter()) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertFamilySupers( + buildJavaClassNameArrayAsserter( + PACKAGE_PREFIX + "ParentClass", + PACKAGE_PREFIX + "GrandpaClass" + ) + ) + .assertFamilyInterfaces( + buildJavaClassNameArrayAsserter( + PACKAGE_PREFIX + "IParentInterfaceFirst", + PACKAGE_PREFIX + "IParentInterfaceFirstFirst", + PACKAGE_PREFIX + "IParentInterfaceFirstSecond", + PACKAGE_PREFIX + "IParentInterfaceSecond", + PACKAGE_PREFIX + "IGrandpaInterfaceFirst", + PACKAGE_PREFIX + "IGrandpaInterfaceFirstFirst" + ) + ) + .assertFamilyTypes( + buildJavaClassNameArrayAsserter( + PACKAGE_PREFIX + "ParentClass", + PACKAGE_PREFIX + "GrandpaClass", + PACKAGE_PREFIX + "IParentInterfaceFirst", + PACKAGE_PREFIX + "IParentInterfaceFirstFirst", + PACKAGE_PREFIX + "IParentInterfaceFirstSecond", + PACKAGE_PREFIX + "IParentInterfaceSecond", + PACKAGE_PREFIX + "IGrandpaInterfaceFirst", + PACKAGE_PREFIX + "IGrandpaInterfaceFirstFirst" + ) + ) + .assertFamilyAnnotationTypes( + buildJavaClassNameArrayAsserter( + PACKAGE_PREFIX + "InheritedAnnotation" + ) + ) + .assertBehaviors( + buildBehaviorSignCodeArrayAsserter( + buildSignCode(PACKAGE_PREFIX + "ChildClass", ""), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfSumIntArray", "int[]"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicInterface"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedInterface"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicStaticClass"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedStaticClass"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicEnum"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnInnerClass"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedEnum"), + buildSignCode( + PACKAGE_PREFIX + "ChildClass", + "methodOfSingleArguments", + PACKAGE_PREFIX + "ChildClass$PublicInterface", + PACKAGE_PREFIX + "ChildClass$ProtectedInterface", + PACKAGE_PREFIX + "ChildClass$PublicStaticClass", + PACKAGE_PREFIX + "ChildClass$ProtectedStaticClass", + PACKAGE_PREFIX + "ChildClass$InnerClass", + PACKAGE_PREFIX + "ChildClass$PublicEnum", + PACKAGE_PREFIX + "ChildClass$ProtectedEnum" + ), + buildSignCode( + PACKAGE_PREFIX + "ChildClass", + "methodOfArrayArguments", + PACKAGE_PREFIX + "ChildClass$PublicInterface[]", + PACKAGE_PREFIX + "ChildClass$ProtectedInterface[]", + PACKAGE_PREFIX + "ChildClass$PublicStaticClass[]", + PACKAGE_PREFIX + "ChildClass$ProtectedStaticClass[]", + PACKAGE_PREFIX + "ChildClass$InnerClass[]", + PACKAGE_PREFIX + "ChildClass$PublicEnum[]", + PACKAGE_PREFIX + "ChildClass$ProtectedEnum[]" + ), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfChildClassWithAnnotation"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfPrivateStatic"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfPrivateNative"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfParentIsAbstract"), + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfParentInterfaceFirstFirstWithAnnotation") + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfReturn() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfSumIntArray", "int[]"), + new BehaviorStructureAsserter() + .assertReturnType(new ClassStructureAsserter().assertJavaClassNameEquals("void")) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicInterface"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$PublicInterface") + .assertAccess(IS_PUBLIC, IS_INTERFACE, IS_STATIC, IS_ABSTRACT) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedInterface"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$ProtectedInterface") + .assertAccess(IS_PROTECTED, IS_INTERFACE, IS_STATIC, IS_ABSTRACT) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicStaticClass"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$PublicStaticClass") + .assertAccess(IS_PUBLIC, IS_STATIC) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedStaticClass"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$ProtectedStaticClass") + .assertAccess(IS_PROTECTED, IS_STATIC) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnPublicEnum"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$PublicEnum") + .assertAccess(IS_PUBLIC, IS_FINAL, IS_ENUM, IS_STATIC) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnInnerClass"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$InnerClass") + .assertAccess() + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfReturnProtectedEnum"), + new BehaviorStructureAsserter() + .assertReturnType( + new ClassStructureAsserter() + .assertJavaClassNameEquals(PACKAGE_PREFIX + "ChildClass$ProtectedEnum") + .assertAccess(IS_PROTECTED, IS_FINAL, IS_ENUM, IS_STATIC) + ) + .assertAccess(IS_PUBLIC) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertExceptionTypes(buildEmptyJavaClassNameArrayAsserter()) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfSingleArguments() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode( + PACKAGE_PREFIX + "ChildClass", + "methodOfSingleArguments", + PACKAGE_PREFIX + "ChildClass$PublicInterface", + PACKAGE_PREFIX + "ChildClass$ProtectedInterface", + PACKAGE_PREFIX + "ChildClass$PublicStaticClass", + PACKAGE_PREFIX + "ChildClass$ProtectedStaticClass", + PACKAGE_PREFIX + "ChildClass$InnerClass", + PACKAGE_PREFIX + "ChildClass$PublicEnum", + PACKAGE_PREFIX + "ChildClass$ProtectedEnum" + ), + new BehaviorStructureAsserter() + .assertAccess(IS_PUBLIC) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfArrayArguments() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode( + PACKAGE_PREFIX + "ChildClass", + "methodOfArrayArguments", + PACKAGE_PREFIX + "ChildClass$PublicInterface[]", + PACKAGE_PREFIX + "ChildClass$ProtectedInterface[]", + PACKAGE_PREFIX + "ChildClass$PublicStaticClass[]", + PACKAGE_PREFIX + "ChildClass$ProtectedStaticClass[]", + PACKAGE_PREFIX + "ChildClass$InnerClass[]", + PACKAGE_PREFIX + "ChildClass$PublicEnum[]", + PACKAGE_PREFIX + "ChildClass$ProtectedEnum[]" + ), + new BehaviorStructureAsserter() + .assertAccess(IS_PUBLIC) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfChildClassWithAnnotation() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfChildClassWithAnnotation"), + new BehaviorStructureAsserter() + .assertExceptionTypes(buildJavaClassNameArrayAsserter( + "java.lang.IllegalStateException", + "java.lang.RuntimeException" + )) + .assertAnnotationTypes(buildJavaClassNameArrayAsserter( + PACKAGE_PREFIX + "InheritedAnnotation" + )) + .assertAccess(IS_PUBLIC) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfPrivateStatic() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfPrivateStatic"), + new BehaviorStructureAsserter() + .assertReturnType(new ClassStructureAsserter().assertJavaClassNameEquals("void")) + .assertAccess(IS_PRIVATE, IS_STATIC) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfPrivateNative() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfPrivateNative"), + new BehaviorStructureAsserter() + .assertReturnType(new ClassStructureAsserter().assertJavaClassNameEquals("void")) + .assertAccess(IS_PRIVATE, IS_NATIVE) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + + @Test + public void test$$ChildClassStructure$$methodOfParentInterfaceFirstFirstWithAnnotation() { + new ClassStructureAsserter() + .assertBehaviors( + new BehaviorStructureCollectionAsserter(ALL) + .assertTargetByKey( + buildSignCode(PACKAGE_PREFIX + "ChildClass", "methodOfParentInterfaceFirstFirstWithAnnotation"), + new BehaviorStructureAsserter() + .assertReturnType(new ClassStructureAsserter().assertJavaClassNameEquals("void")) + .assertAnnotationTypes(buildEmptyJavaClassNameArrayAsserter()) + .assertAccess(IS_PUBLIC) + ) + ) + .assertThat("ChildClass", childClassStructure); + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/AccessAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/AccessAsserter.java new file mode 100644 index 00000000..e35c3cd9 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/AccessAsserter.java @@ -0,0 +1,46 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.Access; + +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.AccessAsserter.AccessIsEnum.*; +import static org.apache.commons.lang3.ArrayUtils.contains; +import static org.junit.Assert.assertEquals; + +public class AccessAsserter implements Asserter { + + public enum AccessIsEnum { + + IS_PUBLIC, + IS_PRIVATE, + IS_PROTECTED, + IS_STATIC, + IS_FINAL, + IS_INTERFACE, + IS_NATIVE, + IS_ABSTRACT, + IS_ENUM, + IS_ANNOTATION + } + + private final AccessIsEnum[] accessIsEnumArray; + + public AccessAsserter(final AccessIsEnum... accessIsEnumArray) { + this.accessIsEnumArray = accessIsEnumArray; + } + + @Override + public void assertThat(final String message, + final Access access) { + assertEquals(message + ":isPublic", access.isPublic(), contains(accessIsEnumArray, IS_PUBLIC)); + assertEquals(message + ":isPrivate", access.isPrivate(), contains(accessIsEnumArray, IS_PRIVATE)); + assertEquals(message + ":isProtected", access.isProtected(), contains(accessIsEnumArray, IS_PROTECTED)); + assertEquals(message + ":isStatic", access.isStatic(), contains(accessIsEnumArray, IS_STATIC)); + assertEquals(message + ":isFinal", access.isFinal(), contains(accessIsEnumArray, IS_FINAL)); + assertEquals(message + ":isInterface", access.isInterface(), contains(accessIsEnumArray, IS_INTERFACE)); + assertEquals(message + ":isNative", access.isNative(), contains(accessIsEnumArray, IS_NATIVE)); + assertEquals(message + ":isAbstract", access.isAbstract(), contains(accessIsEnumArray, IS_ABSTRACT)); + assertEquals(message + ":isEnum", access.isEnum(), contains(accessIsEnumArray, IS_ENUM)); + assertEquals(message + ":isAnnotation", access.isAnnotation(), contains(accessIsEnumArray, IS_ANNOTATION)); + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/Asserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/Asserter.java new file mode 100644 index 00000000..0b6b93af --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/Asserter.java @@ -0,0 +1,7 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +public interface Asserter { + + void assertThat(String message, T target); + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureAsserter.java new file mode 100644 index 00000000..c6f15db3 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureAsserter.java @@ -0,0 +1,82 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.BehaviorStructure; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.AccessAsserter.AccessIsEnum; + +import static org.junit.Assert.assertEquals; + +public class BehaviorStructureAsserter implements Asserter { + + private AccessAsserter accessAsserter; + private String expectedBehaviorName; + private String expectedSignCode; + private ClassStructureAsserter returnTypeClassStructureAsserter; + private ClassStructureCollectionAsserter exceptionTypeClassStructureCollectionAsserter; + private ClassStructureCollectionAsserter annotationTypeClassStructureCollectionAsserter; + + public BehaviorStructureAsserter assertAccess(final AccessIsEnum... accessIsEnumArray) { + this.accessAsserter = new AccessAsserter(accessIsEnumArray); + return this; + } + + public BehaviorStructureAsserter assertBehaviorNameEquals(final String expectedBehaviorName) { + this.expectedBehaviorName = expectedBehaviorName; + return this; + } + + public BehaviorStructureAsserter assertSignCodeEquals(final String expectedSignCode) { + this.expectedSignCode = expectedSignCode; + return this; + } + + public BehaviorStructureAsserter assertReturnType(final ClassStructureAsserter returnTypeClassStructureAsserter) { + this.returnTypeClassStructureAsserter = returnTypeClassStructureAsserter; + return this; + } + + public BehaviorStructureAsserter assertExceptionTypes(final ClassStructureCollectionAsserter exceptionTypeClassStructureCollectionAsserter) { + this.exceptionTypeClassStructureCollectionAsserter = exceptionTypeClassStructureCollectionAsserter; + return this; + } + + public BehaviorStructureAsserter assertAnnotationTypes(final ClassStructureCollectionAsserter annotationTypeClassStructureCollectionAsserter) { + this.annotationTypeClassStructureCollectionAsserter = annotationTypeClassStructureCollectionAsserter; + return this; + } + + @Override + public void assertThat(final String message, + final BehaviorStructure behaviorStructure) { + + final String prefix = message + ":@[" + behaviorStructure.getName() + "]"; + + if (null != accessAsserter) { + accessAsserter.assertThat(prefix + ":Access", behaviorStructure.getAccess()); + } + + if (null != expectedBehaviorName) { + assertEquals(prefix + ":Name", expectedBehaviorName, behaviorStructure.getName()); + } + + if (null != expectedSignCode) { + assertEquals(prefix + ":SignCode", expectedSignCode, behaviorStructure.getSignCode()); + } + + if (null != returnTypeClassStructureAsserter) { + returnTypeClassStructureAsserter + .assertThat(prefix + ":ReturnType", behaviorStructure.getReturnTypeClassStructure()); + } + + if (null != exceptionTypeClassStructureCollectionAsserter) { + exceptionTypeClassStructureCollectionAsserter + .assertThat(prefix + ":ExceptionTypes", behaviorStructure.getExceptionTypeClassStructures()); + } + + if (null != annotationTypeClassStructureCollectionAsserter) { + annotationTypeClassStructureCollectionAsserter + .assertThat(prefix + ":AnnotationTypes", behaviorStructure.getAnnotationTypeClassStructures()); + } + + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureCollectionAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureCollectionAsserter.java new file mode 100644 index 00000000..928750e4 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/BehaviorStructureCollectionAsserter.java @@ -0,0 +1,36 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.BehaviorStructure; +import org.apache.commons.lang3.ArrayUtils; + +public class BehaviorStructureCollectionAsserter extends MappingAsserter { + + public BehaviorStructureCollectionAsserter(Mode mode) { + super(mode); + } + + @Override + protected String takeKey(BehaviorStructure target) { + return target.getSignCode(); + } + + @Override + public BehaviorStructureCollectionAsserter assertTargetByKey(String key, Asserter targetAsserter) { + super.assertTargetByKey(key, targetAsserter); + return this; + } + + public static BehaviorStructureCollectionAsserter buildBehaviorSignCodeArrayAsserter(final String... behaviorSignCodeArray) { + final BehaviorStructureCollectionAsserter behaviorStructureCollectionAsserter = new BehaviorStructureCollectionAsserter(Mode.FULL); + if (ArrayUtils.isNotEmpty(behaviorSignCodeArray)) { + for (final String behaviorSignCode : behaviorSignCodeArray) { + behaviorStructureCollectionAsserter.assertTargetByKey( + behaviorSignCode, + new BehaviorStructureAsserter().assertSignCodeEquals(behaviorSignCode) + ); + } + } + return behaviorStructureCollectionAsserter; + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureAsserter.java new file mode 100644 index 00000000..a98d71fe --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureAsserter.java @@ -0,0 +1,131 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure; +import com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.AccessAsserter.AccessIsEnum; + +import static org.junit.Assert.assertEquals; + +public class ClassStructureAsserter implements Asserter { + + private AccessAsserter accessAsserter; + private String expectedJavaClassName; + + private ClassStructureAsserter superClassStructureAsserter; + private ClassStructureCollectionAsserter interfaceClassStructureCollectionAsserter; + private ClassStructureCollectionAsserter annotationTypeClassStructureCollectionAsserter; + + private ClassStructureCollectionAsserter familySuperClassStructureCollectionAsserter; + private ClassStructureCollectionAsserter familyInterfaceClassStructureCollectionAsserter; + private ClassStructureCollectionAsserter familyTypeClassStructureCollectionAsserter; + private ClassStructureCollectionAsserter familyAnnotationTypeClassStructureCollectionAsserter; + + private BehaviorStructureCollectionAsserter behaviorStructureCollectionAsserter; + + + public ClassStructureAsserter assertAccess(final AccessIsEnum... accessIsEnumArray) { + this.accessAsserter = new AccessAsserter(accessIsEnumArray); + return this; + } + + public ClassStructureAsserter assertJavaClassNameEquals(final String expectedJavaClassName) { + this.expectedJavaClassName = expectedJavaClassName; + return this; + } + + public ClassStructureAsserter assertSuper(ClassStructureAsserter superClassStructureAsserter) { + this.superClassStructureAsserter = superClassStructureAsserter; + return this; + } + + public ClassStructureAsserter assertInterfaces(ClassStructureCollectionAsserter interfaceClassStructureCollectionAsserter) { + this.interfaceClassStructureCollectionAsserter = interfaceClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertAnnotationTypes(ClassStructureCollectionAsserter annotationTypeClassStructureCollectionAsserter) { + this.annotationTypeClassStructureCollectionAsserter = annotationTypeClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertFamilySupers(ClassStructureCollectionAsserter familySuperClassStructureCollectionAsserter) { + this.familySuperClassStructureCollectionAsserter = familySuperClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertFamilyInterfaces(ClassStructureCollectionAsserter familyInterfaceClassStructureCollectionAsserter) { + this.familyInterfaceClassStructureCollectionAsserter = familyInterfaceClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertFamilyTypes(ClassStructureCollectionAsserter familyTypeClassStructureCollectionAsserter) { + this.familyTypeClassStructureCollectionAsserter = familyTypeClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertFamilyAnnotationTypes(ClassStructureCollectionAsserter familyAnnotationTypeClassStructureCollectionAsserter) { + this.familyAnnotationTypeClassStructureCollectionAsserter = familyAnnotationTypeClassStructureCollectionAsserter; + return this; + } + + public ClassStructureAsserter assertBehaviors(BehaviorStructureCollectionAsserter behaviorStructureCollectionAsserter) { + this.behaviorStructureCollectionAsserter = behaviorStructureCollectionAsserter; + return this; + } + + @Override + public void assertThat(final String message, + final ClassStructure classStructure) { + + final String prefix = message + ":@[" + classStructure.getJavaClassName() + "]"; + + if (null != accessAsserter) { + accessAsserter.assertThat(prefix + ":Access", classStructure.getAccess()); + } + + if (null != expectedJavaClassName) { + assertEquals(prefix + ":JavaClassName", expectedJavaClassName, classStructure.getJavaClassName()); + } + + if (null != superClassStructureAsserter) { + superClassStructureAsserter.assertThat(prefix + ":SuperClass", classStructure.getSuperClassStructure()); + } + + if (null != interfaceClassStructureCollectionAsserter) { + interfaceClassStructureCollectionAsserter + .assertThat(prefix + ":Interfaces", classStructure.getInterfaceClassStructures()); + } + + if (null != annotationTypeClassStructureCollectionAsserter) { + annotationTypeClassStructureCollectionAsserter + .assertThat(prefix + ":AnnotationTypes", classStructure.getAnnotationTypeClassStructures()); + } + + + if (null != familySuperClassStructureCollectionAsserter) { + familySuperClassStructureCollectionAsserter + .assertThat(prefix + ":FamilySuperClasses", classStructure.getFamilySuperClassStructures()); + } + + if (null != familyInterfaceClassStructureCollectionAsserter) { + familyInterfaceClassStructureCollectionAsserter + .assertThat(prefix + ":FamilyInterfaces", classStructure.getFamilyInterfaceClassStructures()); + } + + if (null != familyTypeClassStructureCollectionAsserter) { + familyTypeClassStructureCollectionAsserter + .assertThat(prefix + ":FamilyTypes", classStructure.getFamilyTypeClassStructures()); + } + + if (null != familyAnnotationTypeClassStructureCollectionAsserter) { + familyAnnotationTypeClassStructureCollectionAsserter + .assertThat(prefix + ":FamilyAnnotationTypes", classStructure.getFamilyAnnotationTypeClassStructures()); + } + + if (null != behaviorStructureCollectionAsserter) { + behaviorStructureCollectionAsserter + .assertThat(prefix + ":Behaviors", classStructure.getBehaviorStructures()); + } + + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureCollectionAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureCollectionAsserter.java new file mode 100644 index 00000000..c47dac47 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/ClassStructureCollectionAsserter.java @@ -0,0 +1,34 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructure; +import org.apache.commons.lang3.ArrayUtils; + +public class ClassStructureCollectionAsserter extends MappingAsserter { + + public ClassStructureCollectionAsserter(Mode mode) { + super(mode); + } + + @Override + protected String takeKey(ClassStructure target) { + return target.getJavaClassName(); + } + + public static ClassStructureCollectionAsserter buildJavaClassNameArrayAsserter(final String... javaClassNameArray) { + final ClassStructureCollectionAsserter classStructureCollectionAsserter = new ClassStructureCollectionAsserter(Mode.FULL); + if (ArrayUtils.isNotEmpty(javaClassNameArray)) { + for (final String javaClassName : javaClassNameArray) { + classStructureCollectionAsserter.assertTargetByKey( + javaClassName, + new ClassStructureAsserter().assertJavaClassNameEquals(javaClassName) + ); + } + } + return classStructureCollectionAsserter; + } + + public static ClassStructureCollectionAsserter buildEmptyJavaClassNameArrayAsserter() { + return buildJavaClassNameArrayAsserter(); + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/MappingAsserter.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/MappingAsserter.java new file mode 100644 index 00000000..6d98299c --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/asserts/MappingAsserter.java @@ -0,0 +1,81 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts; + +import java.util.*; + +import static com.alibaba.jvm.sandbox.qatest.core.util.matcher.asserts.MappingAsserter.Mode.FULL; +import static org.apache.commons.lang3.StringUtils.join; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public abstract class MappingAsserter implements Asserter> { + + /** + * 匹配模式 + */ + public enum Mode { + + /** + * 对添加的{@code }必须全部断言通过,不允许有遗漏 + * 目标{@code }允许出现不在断言判断集合中的类 + */ + ALL, + + /** + * 对添加的{@code }必须全部断言通过,不允许有遗漏 + * 目标{@code }不允许出现不在断言判断集合中的类 + */ + FULL + } + + + private final Mode mode; + private final Map> mappingOfAsserter = new HashMap>(); + + public MappingAsserter(Mode mode) { + this.mode = mode; + } + + public MappingAsserter assertTargetByKey(final K key, + final Asserter targetAsserter) { + mappingOfAsserter.put(key, targetAsserter); + return this; + } + + abstract protected K takeKey(T target); + + @Override + public void assertThat(String message, Collection targets) { + final Set targetKeySet = new LinkedHashSet(); + for (final T target : targets) { + final K targetKey = takeKey(target); + if (!mappingOfAsserter.containsKey(targetKey)) { + assertFalse( + message + String.format( + ":\"%s\" not contains in \n[\n\t%s\n]", + targetKey, + join(mappingOfAsserter.keySet().toArray(new String[]{}), ",\n\t") + ), + mode == FULL + ); + continue; + } + targetKeySet.add(targetKey); + mappingOfAsserter + .get(targetKey) + .assertThat(message, target); + } + + // 不允许有遗漏匹配,那么所有Key都必须在其中 + for (final K expectedKey : mappingOfAsserter.keySet()) { + assertTrue( + message + String.format( + ":\"%s\" is missing in \n[\n\t%s\n]", + expectedKey, + join(targetKeySet.toArray(new String[]{}), ",\n\t") + ), + targetKeySet.contains(expectedKey) + ); + } + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ChildClass.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ChildClass.java new file mode 100644 index 00000000..cd3a3e60 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ChildClass.java @@ -0,0 +1,119 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public class ChildClass extends ParentClass { + + @Override + public void methodOfSumIntArray(int... intArray) { + + } + + public interface PublicInterface { + } + + protected interface ProtectedInterface { + + } + + public static class PublicStaticClass { + + PublicStaticClass(int... array) { + + } + + PublicStaticClass(String... array) { + + } + + } + + protected static class ProtectedStaticClass { + + } + + class InnerClass { + + } + + public enum PublicEnum { + + } + + protected enum ProtectedEnum { + + } + + public PublicInterface methodOfReturnPublicInterface() { + return null; + } + + public ProtectedInterface methodOfReturnProtectedInterface() { + return null; + } + + public PublicStaticClass methodOfReturnPublicStaticClass() { + return null; + } + + public ProtectedStaticClass methodOfReturnProtectedStaticClass() { + return null; + } + + public PublicEnum methodOfReturnPublicEnum() { + return null; + } + + public InnerClass methodOfReturnInnerClass() { + return null; + } + + public ProtectedEnum methodOfReturnProtectedEnum() { + return null; + } + + public void methodOfSingleArguments( + final PublicInterface publicInterface, + final ProtectedInterface protectedInterface, + final PublicStaticClass publicStaticClass, + final ProtectedStaticClass protectedStaticClass, + final InnerClass innerClass, + final PublicEnum publicEnum, + final ProtectedEnum protectedEnum + ) { + + } + + public void methodOfArrayArguments( + final PublicInterface[] publicInterface, + final ProtectedInterface[] protectedInterface, + final PublicStaticClass[] publicStaticClass, + final ProtectedStaticClass[] protectedStaticClass, + final InnerClass[] innerClass, + final PublicEnum[] publicEnum, + final ProtectedEnum[] protectedEnum + ) { + + } + + + @InheritedAnnotation + public void methodOfChildClassWithAnnotation() throws IllegalStateException, RuntimeException { + + } + + private static void methodOfPrivateStatic() { + + } + + private native void methodOfPrivateNative(); + + @Override + void methodOfParentIsAbstract() { + + } + + @Override + public void methodOfParentInterfaceFirstFirstWithAnnotation() { + + } + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/GrandpaClass.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/GrandpaClass.java new file mode 100644 index 00000000..db8db086 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/GrandpaClass.java @@ -0,0 +1,7 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public class GrandpaClass implements IGrandpaInterfaceFirst { + + + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirst.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirst.java new file mode 100644 index 00000000..6970914f --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirst.java @@ -0,0 +1,4 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public interface IGrandpaInterfaceFirst extends IGrandpaInterfaceFirstFirst { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirstFirst.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirstFirst.java new file mode 100644 index 00000000..a2141845 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IGrandpaInterfaceFirstFirst.java @@ -0,0 +1,4 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public interface IGrandpaInterfaceFirstFirst { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirst.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirst.java new file mode 100644 index 00000000..0a5109b8 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirst.java @@ -0,0 +1,7 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public interface IParentInterfaceFirst extends IParentInterfaceFirstFirst, IParentInterfaceFirstSecond { + + void methodOfSumIntArray(int... intArray); + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstFirst.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstFirst.java new file mode 100644 index 00000000..f3036090 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstFirst.java @@ -0,0 +1,11 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +@InheritedAnnotation +@IllInheritedAnnotation +public interface IParentInterfaceFirstFirst { + + @InheritedAnnotation + @IllInheritedAnnotation + void methodOfParentInterfaceFirstFirstWithAnnotation(); + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstSecond.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstSecond.java new file mode 100644 index 00000000..a2834a62 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceFirstSecond.java @@ -0,0 +1,4 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public interface IParentInterfaceFirstSecond { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceSecond.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceSecond.java new file mode 100644 index 00000000..fde4f6aa --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IParentInterfaceSecond.java @@ -0,0 +1,4 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public interface IParentInterfaceSecond { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IllInheritedAnnotation.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IllInheritedAnnotation.java new file mode 100644 index 00000000..c3ea30d8 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/IllInheritedAnnotation.java @@ -0,0 +1,11 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) +@Retention(RetentionPolicy.RUNTIME) +public @interface IllInheritedAnnotation { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/InheritedAnnotation.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/InheritedAnnotation.java new file mode 100644 index 00000000..81230f19 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/InheritedAnnotation.java @@ -0,0 +1,9 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +import java.lang.annotation.*; + +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR}) +@Retention(RetentionPolicy.RUNTIME) +@Inherited +public @interface InheritedAnnotation { +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ParentClass.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ParentClass.java new file mode 100644 index 00000000..ae2c1428 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/ParentClass.java @@ -0,0 +1,7 @@ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; + +public abstract class ParentClass extends GrandpaClass implements IParentInterfaceFirst, IParentInterfaceSecond { + + abstract void methodOfParentIsAbstract(); + +} diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/package-info.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/package-info.java new file mode 100644 index 00000000..dc45ca28 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/core/util/matcher/target/package-info.java @@ -0,0 +1,26 @@ +/** + * 这个包中的类构建和描述一个类结构,用于测试{@link com.alibaba.jvm.sandbox.core.util.matcher.structure.ClassStructureFactory} + * + *

  • + * 类继承结构 + *
    + * {@code
    + *
    + *   ChildClass
    + *            |
    + *        
    + *            |
    + *            ` ParentClass  IParentInterfaceFirst  IParentInterfaceFirstFirst
    + *                        |            |                               |
    + *                        |            |                               ` IParentInterfaceFirstSecond
    + *                        |            ` IParentInterfaceSecond
    + *                        |
    + *                    
    + *                        |
    + *                        ` GrandpaClass  IGrandpaInterfaceFirst  IGrandpaInterfaceFirstFirst
    + *
    + * }
    + * 
    + *
  • + */ +package com.alibaba.jvm.sandbox.qatest.core.util.matcher.target; \ No newline at end of file diff --git a/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/util/QaClassUtils.java b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/util/QaClassUtils.java new file mode 100644 index 00000000..63556190 --- /dev/null +++ b/sandbox-qatest/src/test/java/com/alibaba/jvm/sandbox/qatest/util/QaClassUtils.java @@ -0,0 +1,110 @@ +package com.alibaba.jvm.sandbox.qatest.util; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.ArrayUtils; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.util.LinkedHashSet; +import java.util.Set; + +import static com.alibaba.jvm.sandbox.core.util.SandboxStringUtils.toInternalClassName; + +public class QaClassUtils { + + /** + * 目标Class文件转换为字节码数组 + * + * @param targetClass 目标Class文件 + * @return 目标Class文件字节码数组 + * @throws IOException 转换出错 + */ + public static byte[] toByteArray(final Class targetClass) throws IOException { + final InputStream is = targetClass.getClassLoader().getResourceAsStream(toResourceName(targetClass.getName())); + try { + return IOUtils.toByteArray(is); + } finally { + IOUtils.closeQuietly(is); + } + } + + public static String toResourceName(String javaClassName) { + return toInternalClassName(javaClassName).concat(".class"); + } + + public static Set> getJdkFamilySuperClasses(Class clazz) { + final Set> familySuperClasses = new LinkedHashSet>(); + for (Class superClass = clazz.getSuperclass(); + superClass != null; + superClass = superClass.getSuperclass()) { + familySuperClasses.add(superClass); + } + return familySuperClasses; + } + + public static Set> getJdkClassInterfaces(Class clazz) { + final Set> interfaceClasses = new LinkedHashSet>(); + if (ArrayUtils.isNotEmpty(clazz.getInterfaces())) { + for (Class interfaceClass : clazz.getInterfaces()) { + interfaceClasses.add(interfaceClass); + interfaceClasses.addAll(getJdkFamilySuperClasses(interfaceClass)); + } + } + return interfaceClasses; + } + + public static Set> getJdkFamilyClassInterface(Class clazz) { + final Set> familyInterfaceClasses = new LinkedHashSet>(); + for (final Class interfaceClass : getJdkClassInterfaces(clazz)) { + familyInterfaceClasses.add(interfaceClass); + familyInterfaceClasses.addAll(getJdkClassInterfaces(interfaceClass)); + } + return familyInterfaceClasses; + } + + /** + * 获取类的所有类型 + *

    + *

  • 所有父类
  • + *
  • 所有父类的接口及这些接口的所有父类
  • + *
  • 所有接口的父类
  • + *

    + * + * @param clazz + * @return + */ + public static Set> getJdkFamilyClassType(Class clazz) { + + // 获取所有的父类 + final Set> familyTypes = new LinkedHashSet>(getJdkFamilyClassInterface(clazz)); + + for (final Class superClass : getJdkFamilySuperClasses(clazz)) { + familyTypes.add(superClass); + familyTypes.addAll(getJdkFamilyClassInterface(superClass)); + } + + // 递归获取所有接口及其父类 + return familyTypes; + } + + public static Set> getJdkAnnotationType(Class clazz) { + final Set> annotationClasses = new LinkedHashSet>(); + if(ArrayUtils.isNotEmpty(clazz.getAnnotations())) { + for (final Annotation annotation : clazz.getAnnotations()) { + if (annotation.getClass().isAnnotation()) { + annotationClasses.add(annotation.getClass()); + } + for (final Class annotationInterfaceClass : annotation.getClass().getInterfaces()) { + if (annotationInterfaceClass.isAnnotation()) { + annotationClasses.add(annotationInterfaceClass); + } + } + } + } + return annotationClasses; + } + + + +} diff --git a/sandbox-spy/pom.xml b/sandbox-spy/pom.xml index b5055bb7..e250a452 100755 --- a/sandbox-spy/pom.xml +++ b/sandbox-spy/pom.xml @@ -6,7 +6,7 @@ com.alibaba.jvm.sandbox sandbox - 1.1.0 + 1.1.1-SNAPSHOT sandbox-spy sandbox-spy ${sandbox.version} diff --git a/sandbox-spy/src/main/java/java/com/alibaba/jvm/sandbox/spy/Spy.java b/sandbox-spy/src/main/java/java/com/alibaba/jvm/sandbox/spy/Spy.java index 19370257..5b6de7fe 100755 --- a/sandbox-spy/src/main/java/java/com/alibaba/jvm/sandbox/spy/Spy.java +++ b/sandbox-spy/src/main/java/java/com/alibaba/jvm/sandbox/spy/Spy.java @@ -75,6 +75,14 @@ public static void init(final String namespace, */ public static void clean(final String namespace) { namespaceMethodHookMap.remove(namespace); + + // 如果是最后的一个命名空间,则需要重新清理Node中所持有的Thread + if (namespaceMethodHookMap.isEmpty()) { + for (int index = 0; index < selfCallBarrier.nodeArray.length; index++) { + selfCallBarrier.nodeArray[index] = new SelfCallBarrier.Node(); + } + } + } private static final SelfCallBarrier selfCallBarrier = new SelfCallBarrier(); @@ -226,7 +234,7 @@ void delete(final Node node) { node.next.pre = node.pre; } // help gc - node.pre = node.next = null; + node.pre = (node.next = null); } // 插入节点