TypeToken + jeneriklerini Kotlin'de Gson ile kullanma


108

Özel bir sınıftan genel tür listesi alamıyorum (Dönüşler):

val turnsType = TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson(pref.turns, turnsType)

o dedi:

cannot access '<init>' it is 'public /*package*/' in 'TypeToken'

Yanıtlar:


237

Bu satır içi eğlenceyi yaratın:

inline fun <reified T> Gson.fromJson(json: String) = fromJson<T>(json, object: TypeToken<T>() {}.type)

ve sonra şu şekilde çağırabilirsiniz:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

Önceki Alternatifler:

ALTERNATİF 1:

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

Koymanız object :ve belirli bir türü girmeniz gerekirfromJson<List<Turns>>


ALTERNATİF 2:

@Cypressious'un bahsettiği gibi, bu şekilde de başarılabilir:

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

olarak kullan:

val turnsType = genericType<List<Turns>>()

4
Bunu sizin için yapan yardımcı bir yöntem de oluşturabilirsiniz:inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
Kirill Rakhman

1
hatta Gson'u bunu yapan yeni bir JSON aşırı yüklemesine sahip olacak şekilde genişletir. Kotlin genişletmek için tasarlanmıştır, bu nedenle Gson'u daha güzel hale getirmek ve TypeTokens'ı gizlemek için genişletin.
Jayson Minard

Bu yanıtın Gson kullanan birçok kişi tarafından görülmesi muhtemel olduğundan, yanıtı daha eksiksiz ve resmi hale getiren önerilen bir düzenleme yaptım. Cevaba açıklamalar ekledim ve sorunu çözmek için kullanılan konular için Kotlin referanslarına bağlantılar ekledim ... böylece insanlar bu konudaki diğer tüm cevapları veya yorumları okumak zorunda kalmazlar. Düzenlemeyi kabul ederseniz, aşağıdaki cevabımı kaldırabilirim.
Jayson Minard

Reddedilenleri düzenle, tüm cevapları ve yorumları tek bir tutarlı cevapta birleştiren tam sürüm için aşağıdaki cevabıma bakın. Kendi cevabınızı kabul ettiniz ama tamamlanmadı.
Jayson Minard

kotlin kaldırma uyarısı: satır içi eğlence <reified T> genericType (): Type? = nesne: TypeToken <T> () {} .type
Juan Mendez

28

Bu sorunu çözer:

val turnsType = object : TypeToken<List<Turns>>() {}.type
val turns = Gson().fromJson<List<Turns>>(pref.turns, turnsType)

İlk satır, aşağı inen bir nesne ifadesi yaratır TypeTokenve ardından Java'yı bundan alır Type. Daha sonra Gson().fromJsonyöntem, işlevin sonucu için belirtilen türe ihtiyaç duyar ( TypeTokenoluşturulanla eşleşmelidir ). Bu çalışmanın iki versiyonu, yukarıdaki gibi veya:

val turns: List<Turns> = Gson().fromJson(pref.turns, turnsType)

Oluşturmayı kolaylaştırmak için TypeToken, reified tür parametrelerini kullanabilmesi için satır içi olması gereken bir yardımcı işlev oluşturabilirsiniz :

inline fun <reified T> genericType() = object: TypeToken<T>() {}.type

Hangisi daha sonra aşağıdaki yollardan biriyle kullanılabilir:

val turnsType = genericType<List<Turns>>()
// or
val turnsType: List<Turns> = genericType()

Ve tüm süreç, Gsonörnek için bir uzantı işlevine sarılabilir :

inline fun <reified T> Gson.fromJson(json: String) = this.fromJson<T>(json, object: TypeToken<T>() {}.type)

Böylece Gson'ı arayabilir ve hiç endişelenmeyebilirsiniz TypeToken:

val turns = Gson().fromJson<Turns>(pref.turns)
// or
val turns: Turns = Gson().fromJson(pref.turns)

Burada Kotlin, atamanın bir tarafından veya diğer tarafından tür çıkarımını kullanıyor ve bir satır içi işlevin tam türü ( TypeTokensilinmeden) geçmesi için yeniden biçimlendirilmiş jenerikler kullanıyor ve bunu kullanarak bir a oluşturmak ve ayrıca Gson'a çağrı yapmak


1
Merhaba @ Jayson, Android Studio'da bu kadar eğlenceli bir şekilde çalışmasını sağlayamadım. İyi görünüyor ama yaptığım zaman tanınmıyorGson().fromJson<kotlin.List<Turns>>(pref.turns)
Juan Saravia

@juancho, "tanınmayan" ın ne anlama geldiğini bana söyleyebilir misin? Derleyici hatası mı? Yukarıdan içe aktarılan uzantı yönteminiz var mı?
Jayson Minard

2
Kodunuzu Android Studio'ya kopyalayıp yapıştırıyorum ve eğlenceyi kotlin sınıfıma aktardım. Söylediklerini yapmaya çalıştım ama bir sebepten dolayı derleyici bana bu eğlencenin olmadığını söyledi. Zaten diğer genişletme işlevlerini kullanıyorum ama önerinizin ne işe yaramadığını bilmiyorum. AS ve Kotlin'in hangi sürümünü kullanıyorsunuz? sadece tekrar denemek için.
Juan Saravia

Bu doğrudan Android stüdyosuyla ilgili değildir, Kotlin bunun içinde veya dışında aynıdır. Bir örnek mi oluşturuyorsunuz Gson()yoksa statikmiş Gsongibi mi? İlkine ihtiyacınız var, bir örneğe.
Jayson Minard

21

Başka bir seçenek (diğerlerinden daha zarif göründüğünden emin değil) şöyle bir çağrı olabilir:

turns = Gson().fromJson(allPurchasesString, Array<Turns>::class.java).toMutableList()

Yani "saf Kotlin" yerine java Array sınıfını tek satırlık kullanıyorsunuz.


2
TypeToken her telefonda güvenilir çalışmadığından, bu benim için en iyi çözüm. Saf kotlin ile kolay tek astar.
LuckyMalaka

11
val obj: MutableList<SaleItemResponse> = Gson().fromJson(messageAfterDecrypt,
    object : TypeToken<List<SaleItemResponse>>() {}.type)

Kotlin'deki veri dizisini ayrıştırma yöntemim bu.


Kısa ve basit, kabul edilen cevap bu olmalıdır.
Umar Ata

6

Ben dönüştürmek için böyle bir şey kullanılmış Tetmek stringve Stringgeri Tkullanarak Gson. Tam olarak aradığınız şey değil ama her ihtimale karşı.

Uzantı bildirme

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)

Kullanım

// 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
        }
    }

5

Bu da işe yarar ve daha basittir

    inline fun <reified T> Gson.fromJson(json: String) : T = 
         this.fromJson<T>(json, T::class.java)

Dönüş türü null yapılabilir olmalıdır. Aksi takdirde Gson kitaplığındaki Java kodu null döndürebilir, ancak Kotlin türün null yapılamaz olduğunu varsayar. Sonuç olarak, Kotlin'de NPE elde edersiniz.
fdermishin

1

generic reified functionGson'dan Kotlin , ArrayList<T>bu kodu kullanmak için seriyi kaldırıyor

 inline fun <reified T> get( ... ): ArrayList<T>{
    
    val str = "[{},{}]"
    
    val type = TypeToken.getParameterized(ArrayList::class.java, T::class.java).type
    
    val t = Gson().fromJson<ArrayList<T>>(str, type)
    

    return t
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.