Consider a Java method which infers its type by Java class as follows:
public <T> T readJson(Class<T> c) throws IOException {
This allows doing something like this:
Map<String, String> map = foo.readJson(Map.class);
In java it will warn about unchecked cast, but it will work correctly. However in Kotlin, this will not be so easy, one could try using:
foo.readJson(Map::class.java)
However if Map<String, String>
will be required, it will not work:
Type inference failed. Expected type mismatch.
required Map<String, String>
found Map<*, *>!
I also tried defining an interface StringMap:
interface StringMap : Map<String, String>
However that does not work either, it will lead to exceptions like this:
Cannot cast ...LinkedTreeMap to ...StringMap
What would be a correct way of doing this?
Kotlin does not have anything like Java raw types (which were left in Java for backward compatibility), and the type system therefore does not allow this kind of unchecked assignment to be made implicitly (star projections, the closest concept to raw types in Kotlin, retain type safety).
You can make an unchecked cast to Map<String, String>
, thus expressing that you are aware of a possible type mismatch at runtime:
@Suppress("UNCHECKED_CAST")
val result = foo.readJson(Map::class.java) as Map<String, String>
You can suppress the unchecked cast warning for a broader scope than just one statement.
A natural improvement of this solution is writing a util function to hide the unchecked cast in it:
@Suppress("UNCHECKED_CAST")
inline fun <reified T: Any> JsonReader.readJson(): T {
val result = readJson(T::class.java)
return result as T
}
This solution uses an inline function with a reified type parameter: the function is transformed and substituted at each of its call sites, with T
replaced by the specified (or inferred) type at compile time .
Usage examples:
val map = jsonReader.readJson<Map<String, String>>()
fun processMap(map: Map<String, String) { /* ... */ }
processMap(jsonReader.readJson()) // Map<String, String> is inferred for this call