Bytebuddy:方法拦截在 Kotlin 中不起作用
Bytebuddy: method interception doesn't work in Kotlin
考虑以下 bytebuddy 程序来拦截方法调用 load()
:
public class ByteJavaBuddyTest {
public static class MemoryDatabase {
public List<String> load(String info) {
return Arrays.asList(info + ": foo", info + ": bar");
}
}
public static class LoggerInterceptor {
public static List<String> log(@SuperCall Callable<List<String>> zuper) throws Exception {
System.out.println("Calling database");
try {
return zuper.call();
} finally {
System.out.println("Returned from database");
}
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
MemoryDatabase loggingDatabase = new ByteBuddy()
.subclass(MemoryDatabase.class)
.method(named("load")).intercept(MethodDelegation.to(LoggerInterceptor.class))
.make()
.load(MemoryDatabase.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded()
.getDeclaredConstructor()
.newInstance();
System.out.println(loggingDatabase.load("qux"));
}
}
它 运行s 并打印:
Calling database
Returned from database
[qux: foo, qux: bar]
转换为 Kotlin 后,它不会 运行 拦截器,也不会抛出任何异常。
object ByteBuddyKotlinTest {
open class MemoryDatabase {
fun load(info: String): List<String> {
return Arrays.asList("$info: foo", "$info: bar")
}
}
object LoggerInterceptor {
@Throws(Exception::class)
fun log(@SuperCall zuper: Callable<List<String>>): List<String> {
println("Calling database")
try {
return zuper.call()
} finally {
println("Returned from database")
}
}
}
@Throws(
NoSuchMethodException::class,
IllegalAccessException::class,
InvocationTargetException::class,
InstantiationException::class
)
@JvmStatic
fun main(args: Array<String>) {
val loggingDatabase = ByteBuddy()
.subclass(MemoryDatabase::class.java)
.method(ElementMatchers.named("load")).intercept(MethodDelegation.to(LoggerInterceptor::class.java))
.make()
.load(MemoryDatabase::class.java.classLoader, ClassLoadingStrategy.Default.WRAPPER)
.loaded
.getDeclaredConstructor()
.newInstance()
println(loggingDatabase.load("qux"))
}
}
打印:
[qux: foo, qux: bar]
因为它没有抛出任何错误,我真的不知道从哪里开始挖掘。
Byte Buddy 通过重写代理方法。如果一个方法在 Kotlin 中没有被声明为 open
,那么它在 Java 字节码中是 final
。如果您打开您的方法,您的逻辑应该再次起作用。
考虑以下 bytebuddy 程序来拦截方法调用 load()
:
public class ByteJavaBuddyTest {
public static class MemoryDatabase {
public List<String> load(String info) {
return Arrays.asList(info + ": foo", info + ": bar");
}
}
public static class LoggerInterceptor {
public static List<String> log(@SuperCall Callable<List<String>> zuper) throws Exception {
System.out.println("Calling database");
try {
return zuper.call();
} finally {
System.out.println("Returned from database");
}
}
}
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
MemoryDatabase loggingDatabase = new ByteBuddy()
.subclass(MemoryDatabase.class)
.method(named("load")).intercept(MethodDelegation.to(LoggerInterceptor.class))
.make()
.load(MemoryDatabase.class.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER)
.getLoaded()
.getDeclaredConstructor()
.newInstance();
System.out.println(loggingDatabase.load("qux"));
}
}
它 运行s 并打印:
Calling database
Returned from database
[qux: foo, qux: bar]
转换为 Kotlin 后,它不会 运行 拦截器,也不会抛出任何异常。
object ByteBuddyKotlinTest {
open class MemoryDatabase {
fun load(info: String): List<String> {
return Arrays.asList("$info: foo", "$info: bar")
}
}
object LoggerInterceptor {
@Throws(Exception::class)
fun log(@SuperCall zuper: Callable<List<String>>): List<String> {
println("Calling database")
try {
return zuper.call()
} finally {
println("Returned from database")
}
}
}
@Throws(
NoSuchMethodException::class,
IllegalAccessException::class,
InvocationTargetException::class,
InstantiationException::class
)
@JvmStatic
fun main(args: Array<String>) {
val loggingDatabase = ByteBuddy()
.subclass(MemoryDatabase::class.java)
.method(ElementMatchers.named("load")).intercept(MethodDelegation.to(LoggerInterceptor::class.java))
.make()
.load(MemoryDatabase::class.java.classLoader, ClassLoadingStrategy.Default.WRAPPER)
.loaded
.getDeclaredConstructor()
.newInstance()
println(loggingDatabase.load("qux"))
}
}
打印:
[qux: foo, qux: bar]
因为它没有抛出任何错误,我真的不知道从哪里开始挖掘。
Byte Buddy 通过重写代理方法。如果一个方法在 Kotlin 中没有被声明为 open
,那么它在 Java 字节码中是 final
。如果您打开您的方法,您的逻辑应该再次起作用。