Почему Котлин выбрасывает IllegalArgumentException при использовании Прокси
Это Kotlin эквивалент Java-кода, использующего InvocationHandler
:
override fun invoke(proxy: Any?, method: Method?, args: Array<out Any>?): Any {
println("before httprequest--->" + args)
val ret = method!!.invoke(obj, args)
println("after httprequest--->")
return ret
}
Java-код:
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
System.out.println("jdk--------->http" + args);
Object result=method.invoke(target, args);
System.out.println("jdk--------->http");
return result;
}
В обоих случаях args
имеет значение null, но если я его запусту, код Kotlin дает исключение
Exception in thread "main" java.lang.IllegalArgumentException: wrong number of arguments
В чем причина этого, поскольку Kotlin использует стандартный класс Java?
1 ответ
Когда вы проходите args
в method!!.invoke(obj, args)
в Kotlin это фактически один аргумент типа массива, и по умолчанию он не разлагается на его элементы как отдельные аргументы.
Чтобы добиться такого поведения, используйте оператор распространения: *args
val ret = method!!.invoke(obj, *args)
С этим синтаксисом args
будет передан так же, как в Java varargs. Например, эти строки кода эквивалентны:
someVarargsFunction("a", "b", "c", "d", "e")
someVarargsFunction("a", "b", *arrayOf("c", "d"), "e")
Примечание: если метод не имеет параметров, args
будет null
и распространение его в Kotlin приведет к NullPointerException
, В качестве обходного пути используйте *(args ?: arrayOfNulls<Any>(0))
и в описанном угловом случае правая часть выбирается и разбивается на ноль аргументов.
Мой пример реализации прокси:
interface SomeInterface {
fun f(a: Int, b: Int): Int
}
val obj = object : SomeInterface {
override fun f(a: Int, b: Int) = a + b
}
val a = Proxy.newProxyInstance(
SomeInterface::class.java.classLoader,
arrayOf(SomeInterface::class.java)) { proxy, method, args ->
println("Before; args: " + args?.contentToString())
val ret = method!!.invoke(obj, *(args ?: arrayOfNulls<Any>(0)))
println("After; result: $ret")
ret
} as SomeInterface
println(a.f(1, 2))
И вывод:
Before; args: [1, 2] After; result: 3 3