I have a mapper like
inline fun <reified DTO_TYPE, reified TYPE> DTO_TYPE.toDomainLayer(): TYPE {
val gson = Gson()
val strJson = gson.toJson(this)
val type = object: TypeToken<TYPE>() {}.type
return gson.fromJson(strJson, type)
}
Now, here if I do it like
inline fun <reified DTO_TYPE, reified TYPE> DTO_TYPE.toDomainLayer(): TYPE {
val gson = Gson()
val strJson = gson.toJson(this)
return gson.fromJson(strJson, TYPE::class.java)
}
Then is the second implementation good to use, or is there anycase where the second implementation will fail?
If you use TYPE::class.java
you get the erased Class
value. This is a problem for generic types. For example if TYPE
is List<MyClass>
, then TYPE::class.java
will give you just List
. This can then later lead to a ClassCastException
when using the deserialized value because Gson does not know the arguments for the type parameters.
Here is an example:
inline fun <reified DTO_TYPE, reified TYPE> DTO_TYPE.toDomainLayer(): TYPE {
val gson = Gson()
val strJson = gson.toJson(this)
return gson.fromJson(strJson, TYPE::class.java)
}
data class InputType(val i: Int)
data class OutputType(val i: Int)
val output: List<OutputType> = listOf(InputType(1)).toDomainLayer()
// ClassCastException: LinkedTreeMap cannot be cast to class OutputType
val first = output.first()
So you have to use object: TypeToken<TYPE>() {}
since that preserves the full parameterized type, such as List<OutputType>
instead of just List
, as mentioned in the question What is Type & TypeToken? (linked in the other answer).
Even better is if you omit the TypeToken.type
call, because this will then use Gson.fromJson(..., TypeToken<T>): T
(requires Gson 2.10 or newer) which verifies that the return type actually matches the type of the TypeToken
at compile time:
val strJson = gson.toJson(this)
val type = object: TypeToken<TYPE>() {}/* .type */
return gson.fromJson(strJson, type)
However, as mentioned by Pawel in the comments, it would be better to use a different JSON library because Gson does not support all Kotlin features. See the "Important" note on Gson's README or this pull request for details.