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 aKType
.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 aClass
argument, which reifies the type parameter to get the target type information