Trying to call existing Java code that expects a Class
as a parameter, I tried code along the lines of this in Kotlin:
package com.example
//Acutally imported Java code in someone elses's library
abstract class JavaCode<T> {
fun doTheThing(thing: Class<JavaCode<T>>) {
//Does work
}
}
//My code
class KotlinCode : JavaCode<String>() {
fun startTheThing() {
doTheThing(KotlinCode::class.java)
} // ^ Type inference failed. Expected type mismatch
}
But that does not compile with the following error:
Type inference failed. Expected type mismatch: inferred type is Class<KotlinCode> but Class<JavaCode<String>> was expected
So I tried to force a cast (as suggested in this answer):
hello(GenericArgument::class.java as Class<Callable<String>>)
But that has a warning:
Unchecked cast: Class<KotlinCode> to Class<JavaCode<String>>
So what is the correct syntax to use? Is this related?
There are several problems in your code.
First, Callable<String?>
is no equal to Callable<String>
. Callable<String?>
means the argument can be String
or null
but Callable<String>
is String
only.
Second, Class<GenericArgument>
does not implement Class<Callable<String>>
but GenericArgument
implements Callable<String>
. they are different. You can change it to use generic instead.
private fun <T : Callable<String>> hello(callable: Class<T>) {
System.out.println(callable.toString())
}
Now, the generic parameter is bound by Callable<String>
.
Third, callable.toString()
probably does not do what you want. callable.toString()
will call the toString()
of the class instead of object, e.g. class com.example.yourclass
. If you want to call the object toString()
. This is the correct one.
override fun call(): String {
hello(GenericArgument())
return "value"
}
private fun <T : Callable<String>> hello(callable: T) {
System.out.println(callable.toString())
}
Moreover, Kotlin allows to pass function as parameter or use SAM for interface. Implementing for Callable
is not necessary.
Edit: As op updated the question.
@Suppress("UNCHECKED_CAST")
fun <T, U : JavaCode<T>> JavaCode<T>.doTheThing2(thing: Class<U>) {
doTheThing(thing as Class<JavaCode<T>>)
}