I'm unable to get a List of generic type from a custom class (Turns):
val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
it said:
cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
I'm unable to get a List of generic type from a custom class (Turns):
val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
it said:
cannot access '<init>' it is 'public /*package*/' in 'TypeToken'
Create this inline fun:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
and then you can call it in this way:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
NOTE: This approach was not possible before in old kotlin plugin versions but now you are able to use it.
Previous Alternatives:
ALTERNATIVE 1:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
You have to put object :
and the specific type in fromJson<List<Turns>>
ALTERNATIVE 2:
As @cypressious mention it can be achieved also in this way:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
use as:
val turnsType = genericType<List<Turns>>()
This solves the problem:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
The first line creates an object expression that descends from TypeToken
and then gets the Java Type
from that. Then the Gson().fromJson
method either needs the type specified for the result of the function (which should match the TypeToken
created). Two versions of this work, as above or:
val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
To make it easier to create the TypeToken
you can create a helper function, which is required to be inline so that it can use reified type parameters:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Which can then be used in either of these ways:
val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()
And the whole process can be wrapped into an extension function for the Gson
instance:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
So that you can just call Gson and not worry about the TypeToken
at all:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Here Kotlin is using type inference from one side of the assignment or the other, and reified generics for an inline function to pass through the full type (without erasure), and using that to construct a TypeToken
and also make the call to Gson
Another option (not sure it looks more elegant than the others) might be a call like this:
turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()
So you are using the java Array class one liner instead of "pure Kotlin".
val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
object : TypeToken<List<SaleItemResponse>>() {}.type)
It's my way to parsing data array in kotlin.
This works as well, and is simpler
inline fun <reified T> Gson.fromJson(json: String) : T =
this.fromJson<T>(json, T::class.java)
I used something like this to convert T
to string
& String
back to T
using Gson
. Not exactly what you are looking for but just in case.
Declaring extension
inline fun <reified T : Any> T.json(): String = Gson().toJson(this, T::class.java)
inline fun <reified T : Any> String.fromJson(): T = Gson().fromJson(this,T::class.java)
Usage
// Passing an object to new Fragment
companion object {
private const val ARG_SHOP = "arg-shop"
@JvmStatic
fun newInstance(shop: Shop) =
ShopInfoFragment().apply {
arguments = Bundle().apply {
putString(ARG_SHOP, shop.json())
}
}
}
// Parsing the passed argument
private lateinit var shop: Shop
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
shop = it.getString(ARG_SHOP).fromJson() ?: return
}
}