Skip to content

Instantly share code, notes, and snippets.

@re-ovo
Created April 27, 2024 12:23
Show Gist options
  • Save re-ovo/e5bd2453824a33f10182e1384b3fdc9d to your computer and use it in GitHub Desktop.
Save re-ovo/e5bd2453824a33f10182e1384b3fdc9d to your computer and use it in GitHub Desktop.
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