Created
April 27, 2024 12:23
-
-
Save re-ovo/e5bd2453824a33f10182e1384b3fdc9d to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
abstract class ReflectionMatcher<T> { | |
protected val rules = arrayListOf<ReflectionMatcher<T>>() | |
abstract fun matches(target: T): Boolean | |
class ClassReflectionMatcher : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
return rules.all { it.matches(target) } | |
} | |
fun anyMatch(vararg matchers: ClassReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
return matchers.any { | |
ClassReflectionMatcher().apply(it).matches(target) | |
} | |
} | |
}) | |
} | |
/** | |
* 匹配类的类型, 使用equals判断 | |
* | |
* @param classes 类的类型, 可以为多个,只要有一个匹配即可 | |
*/ | |
fun oneOf(vararg classes: Class<*>) { | |
rules.add(object : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
return classes.any { it == target } | |
} | |
}) | |
} | |
/** | |
* 匹配类的修饰符, 例如 `Modifier.PUBLIC` or `Modifier.STATIC` | |
* | |
* @param modifiers 修饰符的集合, 例如 `Modifier.PUBLIC` or `Modifier.STATIC` | |
* @see java.lang.reflect.Modifier | |
*/ | |
fun modifier(modifiers: Int) { | |
rules.add(object : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
// modifier参数代表了需要匹配的modifier修饰符的集合, 例如 Modifier.PUBLIC or Modifier.STATIC | |
// 通过位运算来判断是否匹配 | |
return target.modifiers and modifiers == modifiers | |
} | |
}) | |
} | |
/** | |
* 匹配类的名字 | |
* | |
* @param nameMatcher Lambda表达式, 传入类名, 返回是否匹配 | |
* @see java.lang.Class.getName | |
*/ | |
fun className(nameMatcher: (String) -> Boolean) { | |
rules.add(object : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
return nameMatcher(target.name) | |
} | |
}) | |
} | |
/** | |
* 判断类是否存在指定的方法 | |
* | |
* @param methodMatcher Lambda表达式, 传入MethodReflectionMatcher, 用于匹配方法 | |
* @see MethodReflectionMatcher | |
* @see java.lang.Class.getDeclaredMethod | |
*/ | |
fun declaredMethodExists(methodMatcher: MethodReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Class<*>>() { | |
override fun matches(target: Class<*>): Boolean { | |
return target.declaredMethods.any { | |
MethodReflectionMatcher().apply(methodMatcher).matches(it) | |
} | |
} | |
}) | |
} | |
} | |
class MethodReflectionMatcher : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return rules.all { it.matches(target) } | |
} | |
fun anyMatch(vararg matchers: MethodReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return matchers.any { | |
MethodReflectionMatcher().apply(it).matches(target) | |
} | |
} | |
}) | |
} | |
/** | |
* 匹配方法的名字 | |
* | |
* @param name Lambda表达式, 传入方法名, 返回是否匹配 | |
*/ | |
fun methodName(name: (String) -> Boolean) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return name(target.name) | |
} | |
}) | |
} | |
/** | |
* 匹配方法的修饰符 | |
* | |
* @param modifiers 修饰符的集合, 例如 `Modifier.PUBLIC` or `Modifier.STATIC` | |
* @see java.lang.reflect.Modifier | |
*/ | |
fun modifier(modifiers: Int) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
// modifier参数代表了需要匹配的modifier修饰符的集合, 例如 Modifier.PUBLIC or Modifier.STATIC | |
// 通过位运算来判断是否匹配 | |
return target.modifiers and modifiers == modifiers | |
} | |
}) | |
} | |
/** | |
* 匹配方法的返回类型 | |
* | |
* 如果想直接匹配确定的返回类型, 可以使用 | |
* | |
* ``` | |
* returnType { oneOf(XXX::class.java) } | |
* ``` | |
* | |
* @param classMatcher Lambda表达式, 传入ClassReflectionMatcher, 用于匹配返回类型 | |
* @see ClassReflectionMatcher | |
* @see java.lang.reflect.Method.getReturnType | |
*/ | |
fun returnType(classMatcher: ClassReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return ClassReflectionMatcher().apply(classMatcher).matches(target.returnType) | |
} | |
}) | |
} | |
/** | |
* 匹配方法的参数个数 | |
* | |
* @param count 参数个数 | |
* @see java.lang.reflect.Method.getParameterCount | |
*/ | |
fun parameterCount(count: Int) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return target.parameterCount == count | |
} | |
}) | |
} | |
/** | |
* 匹配方法的参数类型 | |
* | |
* @param index 参数的下标 | |
* @param defaultValue 如果参数不存在, 是否匹配 | |
* @param classMatcher Lambda表达式, 传入ClassReflectionMatcher, 用于匹配参数类型 | |
*/ | |
fun parameterType(index: Int, defaultValue: Boolean, classMatcher: ClassReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
val type = target.parameterTypes.getOrNull(index) ?: return defaultValue | |
return ClassReflectionMatcher().apply(classMatcher).matches(type) | |
} | |
}) | |
} | |
/** | |
* 匹配方法字节码 | |
* | |
* @param matcher Lambda表达式, 传入MethodByteCodeMatcher, 用于匹配方法字节码 | |
* @see MethodByteCodeMatcher | |
*/ | |
fun byteCode(matcher: MethodByteCodeMatcher.() -> Unit) { | |
rules.add(MethodByteCodeMatcher().apply(matcher)) | |
} | |
} | |
class FieldReflectionMatcher : ReflectionMatcher<Field>() { | |
override fun matches(target: Field): Boolean { | |
return rules.all { it.matches(target) } | |
} | |
/** | |
* 匹配字段的名字 | |
* | |
* @param name Lambda表达式, 传入字段名, 返回是否匹配 | |
* @see java.lang.reflect.Field.getName | |
*/ | |
fun fieldName(name: (String) -> Boolean) { | |
rules.add(object : ReflectionMatcher<Field>() { | |
override fun matches(target: Field): Boolean { | |
return name(target.name) | |
} | |
}) | |
} | |
/** | |
* 匹配字段的修饰符 | |
* | |
* @param modifiers 修饰符的集合, 例如 `Modifier.PUBLIC` or `Modifier.STATIC` | |
* @see java.lang.reflect.Modifier | |
*/ | |
fun modifier(modifiers: Int) { | |
rules.add(object : ReflectionMatcher<Field>() { | |
override fun matches(target: Field): Boolean { | |
// modifier参数代表了需要匹配的modifier修饰符的集合, 例如 Modifier.PUBLIC or Modifier.STATIC | |
// 通过位运算来判断是否匹配 | |
return target.modifiers and modifiers == modifiers | |
} | |
}) | |
} | |
/** | |
* 匹配字段的类型 | |
* | |
* 如果想直接匹配确定的字段类型, 可以使用 | |
* | |
* ``` | |
* fieldType { oneOf(XXX::class.java) } | |
* ``` | |
* | |
* @param classMatcher Lambda表达式, 传入ClassReflectionMatcher, 用于匹配字段类型 | |
* @see ClassReflectionMatcher | |
* @see java.lang.reflect.Field.getType | |
*/ | |
fun fieldType(classMatcher: ClassReflectionMatcher.() -> Unit) { | |
rules.add(object : ReflectionMatcher<Field>() { | |
override fun matches(target: Field): Boolean { | |
return ClassReflectionMatcher().apply(classMatcher).matches(target.type) | |
} | |
}) | |
} | |
} | |
class MethodByteCodeMatcher : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
return rules.all { it.matches(target) } | |
} | |
fun jumpInsnOpcodes(vararg opcodes: Int) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
var matched = false | |
target.visitor(object : MethodVisitor(Opcodes.ASM9) { | |
override fun visitJumpInsn(opcode: Int, label: Label?) { | |
if (opcodes.contains(opcode)) { | |
matched = true | |
} | |
} | |
}) | |
return matched | |
} | |
}) | |
} | |
fun insnOpcodes(vararg opcodes: Int) { | |
rules.add(object : ReflectionMatcher<Method>() { | |
override fun matches(target: Method): Boolean { | |
target.visitor(object : MethodVisitor(Opcodes.ASM9) { | |
override fun visitInsn(opcode: Int) { | |
if (opcodes.contains(opcode)) { | |
return | |
} | |
} | |
}) | |
return false | |
} | |
}) | |
} | |
} | |
} | |
fun classMatcher( | |
matcher: ReflectionMatcher.ClassReflectionMatcher.() -> Unit | |
): ReflectionMatcher.ClassReflectionMatcher { | |
return ReflectionMatcher.ClassReflectionMatcher().apply(matcher) | |
} | |
fun methodMatcher( | |
matcher: ReflectionMatcher.MethodReflectionMatcher.() -> Unit | |
): ReflectionMatcher.MethodReflectionMatcher { | |
return ReflectionMatcher.MethodReflectionMatcher().apply(matcher) | |
} | |
fun reflectionMatcher( | |
matcher: ReflectionMatcher.FieldReflectionMatcher.() -> Unit | |
): ReflectionMatcher.FieldReflectionMatcher { | |
return ReflectionMatcher.FieldReflectionMatcher().apply(matcher) | |
} | |
fun Class<*>.ensureMatching(matcher: ReflectionMatcher.ClassReflectionMatcher.() -> Unit): Class<*> { | |
val classMatcher = ReflectionMatcher.ClassReflectionMatcher().apply(matcher) | |
if (!classMatcher.matches(this)) { | |
throw IllegalArgumentException("Class $this does not match the given matcher") | |
} | |
return this | |
} | |
fun Method.ensureMatching(matcher: ReflectionMatcher.MethodReflectionMatcher.() -> Unit): Method { | |
val methodMatcher = ReflectionMatcher.MethodReflectionMatcher().apply(matcher) | |
if (!methodMatcher.matches(this)) { | |
throw IllegalArgumentException("Method $this does not match the given matcher") | |
} | |
return this | |
} | |
fun Field.ensureMatching(matcher: ReflectionMatcher.FieldReflectionMatcher.() -> Unit): Field { | |
val fieldMatcher = ReflectionMatcher.FieldReflectionMatcher().apply(matcher) | |
if (!fieldMatcher.matches(this)) { | |
throw IllegalArgumentException("Field $this does not match the given matcher") | |
} | |
return this | |
} | |
fun Class<*>.findMatchingDeclaredMethods(matcher: ReflectionMatcher.MethodReflectionMatcher.() -> Unit): Set<Method> { | |
val methodMatcher = ReflectionMatcher.MethodReflectionMatcher().apply(matcher) | |
return declaredMethods.filter { methodMatcher.matches(it) }.toSet() | |
} | |
fun Class<*>.findMatchingDeclaredFields(matcher: ReflectionMatcher.FieldReflectionMatcher.() -> Unit): Set<Field> { | |
val fieldMatcher = ReflectionMatcher.FieldReflectionMatcher().apply(matcher) | |
return declaredFields.filter { fieldMatcher.matches(it) }.toSet() | |
} | |
fun Method.visitor(reader: MethodVisitor) { | |
val clazzLoader = this.declaringClass.classLoader | |
val classReader = ClassReader( | |
clazzLoader.getResourceAsStream(this.declaringClass.name.replace(".", "/") + ".class") | |
) | |
classReader.accept(object : ClassVisitor(Opcodes.ASM9) { | |
override fun visitMethod( | |
access: Int, | |
name: String?, | |
descriptor: String?, | |
signature: String?, | |
exceptions: Array<out String>? | |
): MethodVisitor? { | |
if ( | |
name == this@visitor.name | |
&& descriptor == Type.getMethodDescriptor(this@visitor) | |
&& access == this@visitor.modifiers | |
) { | |
return reader | |
} | |
return null | |
} | |
}, 0) | |
} | |
fun main() { | |
val method = Test::class.java | |
.ensureMatching { | |
className { it.endsWith("Test") } | |
modifier(Modifier.PUBLIC) | |
} | |
.findMatchingDeclaredMethods { | |
methodName { it.startsWith("get") } | |
modifier(Modifier.PRIVATE) | |
returnType { | |
oneOf(String::class.java) | |
} | |
byteCode { | |
jumpInsnOpcodes(Opcodes.IFEQ, Opcodes.IFNE, Opcodes.IFNULL, Opcodes.IFNONNULL) | |
} | |
anyMatch( | |
{ | |
parameterCount(4) | |
}, | |
{ | |
parameterCount(2) | |
} | |
) | |
} | |
.first() | |
println(method) | |
//println(method.invoke(Test(), 123)) | |
method.visitor(object : MethodVisitor(Opcodes.ASM9) { | |
override fun visitJumpInsn(opcode: Int, label: Label?) { | |
println("visitJumpInsn: $opcode, $label") | |
} | |
override fun visitMethodInsn( | |
opcode: Int, | |
owner: String?, | |
name: String?, | |
descriptor: String?, | |
isInterface: Boolean | |
) { | |
println("visitMethodInsn: $opcode, $owner, $name, $descriptor, $isInterface") | |
Opcodes.ASM9 | |
} | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment