generics - Cómo usar los genéricos TypeToken+con Gson en Kotlin
(6)
Crea esta diversión en línea:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
y luego puedes llamarlo de esta manera:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
NOTA : Este enfoque no era posible antes en las versiones antiguas del complemento kotlin, pero ahora puede usarlo.
Alternativas anteriores:
ALTERNATIVA 1:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
Tienes que poner
object :
y el tipo específico en
fromJson<List<Turns>>
ALTERNATIVA 2:
Como @cypressious menciona, también se puede lograr de esta manera:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
usar como:
val turnsType = genericType<List<Turns>>()
No puedo obtener una Lista de tipos genéricos de una clase personalizada (Turnos):
val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)
decía:
cannot access ''<init>'' it is ''public /*package*/'' in ''TypeToken''
Esto resuelve el problema:
val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)
La primera línea crea una
expresión de objeto
que desciende de
TypeToken
y luego obtiene el
Type
Java de eso.
Luego, el método
Gson().fromJson
necesita el tipo especificado para el resultado de la función (que debe coincidir con el
TypeToken
creado).
Dos versiones de este trabajo, como arriba o:
val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)
Para facilitar la creación de
TypeToken
, puede crear una función auxiliar, que debe estar en
inline
para que pueda usar
parámetros de tipo reified
:
inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Que luego se puede utilizar de cualquiera de estas formas:
val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()
Y todo el proceso se puede incluir en una función de extensión para la instancia de
Gson
:
inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)
Para que pueda llamar a Gson y no preocuparse por el
TypeToken
:
val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)
Aquí Kotlin está usando la inferencia de tipos de un lado de la tarea u otro, y ha modificado genéricos para que una función en línea pase a través del tipo completo (sin borrado), y la usa para construir un
TypeToken
y también hacer la llamada a Gson
Esto también funciona y es más simple
inline fun <reified T> Gson.fromJson(json: String) : T =
this.fromJson<T>(json, T::class.java)
Otra opción (no estoy seguro de que se vea más elegante que las otras) podría ser una llamada como esta:
turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()
Entonces está utilizando el java Array class one liner en lugar de "pure Kotlin".
Utilicé algo como esto para convertir
T
a
string
y
String
nuevo a
T
usando
Gson
.
No es exactamente lo que está buscando, pero por las dudas.
Declarando extensión
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)
Uso
// 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
}
}
val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
object : TypeToken<List<SaleItemResponse>>() {}.type)
Es mi manera de analizar la matriz de datos en kotlin.