Trying to convert some Java code to Kotlin, the Java code includes a call to a library method TableUtils.dropTable
which is implemented in Java. The Java method signature of this method is
public static <T, ID> int dropTable(ConnectionSource connectionSource, Class<T> dataClass, boolean ignoreErrors) throws SQLException
When calling the method from Java it compiles fine even though the type variable ID
is not known. For example:
public void method(ConnectionSource connectionSource, Class<? extends IRecordObject> clazz) {
try {
TableUtils.dropTable(connectionSource, clazz, true); // this compiles fine
} catch (SQLException e) {
e.printStackTrace();
}
}
After converting to Kotlin, the corresponding function fails to compile because the type variable ID
cannot be inferred:
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) {
try {
TableUtils.dropTable(connectionSource, clazz, true) // compile error: "Not enough information to infer type variable ID"
} catch (e: SQLException) {
e.printStackTrace()
}
}
I don't know how I can explicitly specify the type variables, as one of them would be a wildcard, and you aren't allowed to use wildcards in type variables when calling functions. For example:
TableUtils.dropTable<out IRecordObject,Long>(connectionSource, clazz, true) // this also fails to compile, "Projections are not allowed on type arguments of functions and properties"
So how can I specify the type variable ID
here to allow the code to compile in Kotlin?
The type ID
is unused in the function signature, so it doesn't matter what it is. For the Kotlin version, you can literally put any type there to make the error go away. Whichever type you use will have no effect on the compiled code because of type erasure. You can use an underscore to allow T
to be inferred.
fun method(connectionSource: ConnectionSource?, clazz: Class<out IRecordObject>) {
try {
TableUtils.dropTable<_, Unit>(connectionSource, clazz, true)
} catch (e: SQLException) {
e.printStackTrace()
}
}
I actually don't know how you can write out the type and make it work instead of using inference. The only way I can think to make it work is to make this function generic so you can use an invariant Class type:
fun <T: IRecordObject> method(clazz: Class<T>) {
JavaFoo.dropTable<T, Unit>(clazz, true)
}
I think the Java method signature should have used Class<? extends T>
for more proper flexibility and probably should have omitted ID
since it is effectively useless.