Home > other >  Kotlin: Generic types in Kotlin
Kotlin: Generic types in Kotlin

Time:07-12

To get the class definition to be used for example for json deserialization the following can be used in Kotlin:

Map::class.java

A example usage is the following:

val map =  mapper.readValue(json, Map::class.java)

But now how to have the generic type definition?

Something like this does not compile:

val map =  mapper.readValue(decodedString, Map<String, String>::class.java)

So my question is: What is the generic equivalent to *::class.java

CodePudding user response:

Class<T> (in Java) or KClass<T> (in Kotlin) can only represent classes, not all types. If the API you're using only uses Class<T> or KClass<T>, it simply doesn't support generic types (at least in those functions).

Instead, KType (or Type in Java) is the proper type to use to represent the complete type information including generics. You could use it this way:

val myMapType: KType = typeOf<Map<String,String>>()

Unfortunately, KType doesn't have a type parameter (it's not KType<T>), and that makes it impossible to use for compile-time type checking: you can't have the equivalent of fun deserialize(Input, KClass<T>): T using KType instead of KClass, because you can't define the T for the return type by using only a KType argument.

There are several tricks to work around this:

  • In both Java and Kotlin, one of the ways is to get this information through inheritance by providing a generic superclass and inheriting from it.

    In general, serialization APIs (especially the deserializing part) provide workarounds using this, such as Jackson's TypeReference or Gson's TypeToken. It's basically their version of Type but with a type parameter to have some compile-time type safety.

  • In Kotlin, there is sometimes another way depending on the situation: making use of reified type parameters. Using inline functions, the compiler can know more information at compile time about the type parameters by replacing them with the actual inferred type at the call site when inlining the function's body. This allows things like T::class in the inline function's body. This is how you can get functions like typeOf to get a KType.

    Some Kotlin-specific APIs of deserialization libraries use inline functions to remove the hassle from the user, and get type information directly. This is what jackson-module-kotlin does by providing an inline readValue extension without a Class argument, which reifies the type parameter to get the target type information

  • Related