कोटलिन में Gson के साथ TypeToken + जेनेरिक का उपयोग कैसे करें


108

मैं एक कस्टम वर्ग (सामान्य) से सामान्य प्रकार की सूची प्राप्त करने में असमर्थ हूं:

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

यह कहा:

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

जवाबों:


236

यह इनलाइन मजेदार बनाएं:

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

और फिर आप इसे इस तरह से कॉल कर सकते हैं:

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

पिछले विकल्प:

वैकल्पिक 1:

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

आपको object :और विशिष्ट प्रकार में डालना होगाfromJson<List<Turns>>


वैकल्पिक 2:

@ उल्लेख के रूप में यह इस तरह से भी प्राप्त किया जा सकता है:

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

इस रूप में उपयोग करें:

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

4
आप एक सहायक विधि भी बना सकते हैं जो आपके लिए है:inline fun <reified T> genericType() = object: TypeToken<T>() {}.type
किरील रहमान

1
या यहाँ तक कि Gson से एक नया अधिभार है जो कि ऐसा करता है। कोटलिन का विस्तार करने के लिए डिज़ाइन किया गया है, इसलिए इसे अच्छा बनाने के लिए गेसन का विस्तार करें और टाइपकोकेंस को छिपाएं।
जैसन मिनार्ड

मैंने एक सुझाया हुआ संपादन किया, जो उत्तर को अधिक पूर्ण और औपचारिक बनाता है क्योंकि इस उत्तर को बहुत से लोग देख सकते हैं जो ग्सन का उपयोग करते हैं। मैंने उत्तर में स्पष्टीकरण जोड़ा, और समस्या को हल करने के लिए उपयोग किए जाने वाले विषयों के लिए कोटलिन संदर्भों के लिंक ... ताकि लोगों को अन्य सभी उत्तरों या टिप्पणियों को पढ़ने की ज़रूरत न हो जो इसमें गए थे। यदि आप संपादन स्वीकार करते हैं तो मैं नीचे अपना उत्तर हटा सकता हूं।
जैसन मिनार्ड

संपादित अस्वीकृत, एक पूर्ण संस्करण के लिए नीचे दिए गए मेरे उत्तर को देखें जो सभी उत्तरों और टिप्पणियों को एक सुसंगत उत्तर में जोड़ता है। आपने स्वयं अपना उत्तर स्वीकार कर लिया है लेकिन यह पूर्ण नहीं है।
जैसन मिनार्ड

कोटलिन चेतावनी को हटाना: इनलाइन मस्ती <re T / genericType (): प्रकार? = वस्तु: टाइपटोकन <टी> () {} .type
जुआन मेंडेज़

28

इससे समस्या हल होती है:

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

पहली पंक्ति एक ऑब्जेक्ट एक्सप्रेशन बनाती है जो इससे उतरती है TypeTokenऔर फिर उसी से जावा Typeप्राप्त करती है। फिर Gson().fromJsonविधि को या तो फ़ंक्शन के परिणाम के लिए निर्दिष्ट प्रकार की आवश्यकता होती है (जिसे TypeTokenनिर्मित से मेल खाना चाहिए )। इस काम के दो संस्करण, ऊपर या नीचे:

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

बनाने में आसान बनाने के लिए TypeTokenआप एक हेल्पर फंक्शन बना सकते हैं, जिसमें इनलाइन होना आवश्यक है ताकि वह रीइंस्टाल्ड टाइप पैरामीटर का उपयोग कर सके :

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

जो तब इनमें से किसी भी तरीके से उपयोग किया जा सकता है:

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

और पूरी प्रक्रिया को Gsonउदाहरण के लिए एक एक्सटेंशन फ़ंक्शन में लपेटा जा सकता है :

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

ताकि आप सिर्फ गन्स को कॉल कर सकें और बिल्कुल भी चिंता न करें TypeToken:

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

यहाँ कोटलिन असाइनमेंट के एक तरफ या दूसरे से टाइप इंट्रैक्शन का इस्तेमाल कर रहा है, और इनलाइन फंक्शन के लिए रिवाइज्ड जेनेरिक को फुल टाइप (बिना TypeTokenमिटाये) से गुजरने के लिए इस्तेमाल कर रहा है, और इसका इस्तेमाल करके गन्स को कॉल भी कर सकता है


1
हाय @Jayson, मैं Android स्टूडियो में इस इनलाइन मज़ा काम करता है नहीं कर सका। ठीक लगता है, लेकिन यह पहचाना नहीं जाता है जब मैं करता हूंGson().fromJson<kotlin.List<Turns>>(pref.turns)
जुआन साराविया

@ जुआनचो क्या आप मुझे टेली कर सकते हैं जो "मान्यता प्राप्त नहीं" का मतलब है? एक संकलक त्रुटि? आपके पास विस्तार की विधि आयातित और ऊपर से उपलब्ध है?
जैसन मिनार्ड

2
मैं एंड्रॉइड स्टूडियो में आपके कोड को कॉपी और पेस्ट करता हूं और अपने कोटलिन वर्ग में मज़ा आयात करता हूं। मैंने वही करने की कोशिश की जो आपने कही थी लेकिन किसी कारण से कंपाइलर ने मुझे बताया कि यह मज़ा मौजूद नहीं है। मैं पहले से ही अन्य extention कार्यों का उपयोग कर रहा हूं, लेकिन मुझे नहीं पता कि आपका सुझाव क्या काम नहीं करता है। एएस और कोटलिन के कौन से संस्करण का उपयोग कर रहे हैं? बस इसे फिर से कोशिश करने के लिए।
जुआन सरविया 13

यह सीधे एंड्रॉइड स्टूडियो से संबंधित नहीं है, कोटलिन उसी के अंदर या बाहर समान है। क्या आप इसका उदाहरण बना रहे हैं Gson()या जैसे Gsonकि यह स्थिर है? आपको सबसे पहले, एक उदाहरण की आवश्यकता है।
जैसन मिनार्ड

21

एक अन्य विकल्प (यह सुनिश्चित नहीं है कि यह दूसरों की तुलना में अधिक सुरुचिपूर्ण दिखता है) इस तरह से एक कॉल हो सकता है:

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

तो आप "शुद्ध कोटलिन" के बजाय जावा अर्रे क्लास वन लाइनर का उपयोग कर रहे हैं।


2
चूंकि TypeToken विश्वसनीय हर फोन पर काम नहीं करता है, यह मेरे लिए सबसे अच्छा समाधान है। शुद्ध कोटलिन के साथ एक आसान एक लाइनर।
लकीमलाका

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

यह कोटलिन में डेटा ऐरे को पार्स करने का मेरा तरीका है।


यह स्वीकृत उत्तर होना चाहिए, छोटा और सरल।
उमर अता

6

मैंने कुछ इस तरह से उपयोग Tकिया stringऔर उपयोग में Stringवापस लाया । ठीक वही नहीं जो आप ढूंढ रहे हैं लेकिन सिर्फ मामले में।TGson

विस्तार की घोषणा

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)

प्रयोग

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

यह भी काम करता है, और सरल है

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

वापसी प्रकार अशक्त होना चाहिए। अन्यथा Gson लाइब्रेरी में जावा कोड अशक्त हो सकता है, लेकिन कोटलिन मानता है कि गैर-अशक्त है। नतीजतन, आपको कोटलिन में एनपीई मिलता है।
fdermishin

1

Kotlin generic reified functionGson के लिए deserialize ArrayList<T>इस कोड का उपयोग

 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
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.