given following Kotlin class:
class Foo {
public fun bar(i: Int = 0): Int = 2 * i
}
How should I call 'bar' function without any parameter from a java/groovy code?
def f = new Foo()
f.bar() //throws: java.lang.IllegalArgumentException: Parameter specified as non-null contains null
You can do this now in Kotlin. For your class method, use the @JvmOverloads
annotation.
class Foo {
@JvmOverloads public fun bar(name: String = "World"): String = "Hello $name!"
}
Now simply call it from Java:
Foo foo = new Foo();
System.out.println(foo.bar());
System.out.println(foo.bar("Frank"));
Outputs the following:
Hello World!
Hello Frank!
I'll post the real answer shortly, but if anyone is wanting to do this from reflection, here is how the code would look. Much more complicated, but educational about how to use Kotlin reflection for KCallable
.
Here is the class to call:
class Foo {
public fun bar(name: String = "World"): String = "Hello $name!"
}
Then we need a utility class in Kotin that can receive an instance of a class, a method from java reflection, and the parameters by name. This only works with non-primitives:
class KReflectHelper {
companion object {
@Suppress("UNCHECKED_CAST")
@JvmStatic fun <T> callKotlinMethodWithNamedParms(instance: Any, method: Method, parmMap: Map<String, Any>): T {
val callable: KFunction<T> = method.kotlinFunction as? KFunction<T> ?: throw IllegalStateException("Method is not a Kotlin method")
val unusedParms = HashSet(parmMap.keys)
val callableParms = hashMapOf<KParameter, Any?>()
callable.parameters.map { parm ->
if (parm.kind == KParameter.Kind.INSTANCE) {
callableParms.put(parm, instance)
} else if (parm.kind == KParameter.Kind.VALUE && parmMap.contains(parm.name)) {
unusedParms.remove(parm.name)
callableParms.put(parm, parmMap.get(parm.name))
} else if (parm.kind == KParameter.Kind.VALUE) {
if (parm.isOptional) {
// default value will be used!
} else {
throw IllegalStateException("Missing required parameter ${parm.name}")
}
} else {
throw IllegalStateException("Cannot call methods that are not direct instance methods")
}
}
if (unusedParms.isNotEmpty()) {
throw IllegalStateException("Unrecognized parameters passed to function: $unusedParms")
}
return method.kotlinFunction?.callBy(callableParms) as T
}
}
}
Now that static method can be called from Java, but it isn't so much fun. A code generator would really be required. Calling it from Kotlin is much easier and some frameworks (such as Klutter and Kovert) already use something along these lines.
Foo foo = new Foo();
System.out.println(foo.bar("Frank"));
Method barMethod = Foo.class.getMethod("bar", String.class);
Map<String, Object> parms = new HashMap<String, Object>();
parms.put("name", "David");
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
// now call using the default
parms.clear();
System.out.println(KReflectHelper.callKotlinMethodWithNamedParms(foo, barMethod, parms));
Ouput:
Hello Frank!
Hello David!
Hello World!