Kotlinで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'

回答:


235

このインラインの楽しみを作成します。

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:

@cypressiousが言及するように、これは次の方法でも達成できます。

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

使用:

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

4
また、あなたのためにそれを行うヘルパーメソッドを作成することができますinline fun <reified T> genericType() = object: TypeToken<T>() {}.type
キリルRakhman

1
または、Gsonを拡張して、これを行うfromJsonの新しいオーバーロードを追加します。Kotlinは拡張するように設計されているため、Gsonを拡張してそれをより良くし、TypeTokenを非表示にします。
Jayson Minard、2015年

この回答はGsonを使用する多くの人に見られる可能性が高いので、回答をより完全で正式なものにする編集案を作成しました。私は回答に説明を追加し、問題を解決するために使用されるトピックのKotlin参照へのリンクを追加しました。これにより、他のすべての回答やコメントを読む必要がなくなります。編集を承認した場合、以下の回答を削除できます。
Jayson Minard、2015

編集が拒否されました。すべての回答とコメントを1つの首尾一貫した回答にまとめた完全版については、以下の私の回答を参照してください。あなたは自分の答えを受け入れましたが、それは完全ではありません。
Jayson Minard、2015

kotlin警告の削除:インラインfun <reified T> genericType():Type?=オブジェクト:TypeToken <T>(){} .type
フアンメンデス

28

これは問題を解決します:

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

1行目は、子孫のオブジェクト式を作成し、そこからTypeTokenJava Typeを取得します。次に、Gson().fromJsonメソッドには、関数の結果に指定されたタイプが必要です(TypeToken作成されたものと一致する必要があります)。上記のように、または次のようにこの2つのバージョンが機能します。

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)

したがって、Gsonを呼び出すだけで、心配する必要はありませんTypeToken

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

ここでKotlinは、割り当ての一方または他方からの型推論を使用しており、インライン関数のジェネリックTypeTokenを具体化して(消去なしで)完全な型を通過させ、それを使用してを構築し、Gsonを呼び出します


1
こんにちは@Jayson、私はそれをAndroid Studioでこのインライン楽しいように動作させることができませんでした。大丈夫のようですが、私が行っても認識されませんGson().fromJson<kotlin.List<Turns>>(pref.turns)
ファンサラビア、2015年

@juancho「認識されない」の意味を教えてください。コンパイラエラー?あなたは拡張メソッドをインポートして上から利用できますか?
Jayson Minard、2015

2
コードをコピーしてAndroid Studioに貼り付け、楽しみをkotlinクラスにインポートしました。私はあなたが言ったことをやろうとしましたが、何らかの理由でコンパイラーはこの面白さは存在しないと言っています。私はすでに他の拡張関数を使用していますが、あなたの提案がうまくいかないのかわかりません。ASとKotlinのどのバージョンを使用していますか?もう一度やり直してください。
ファンサラビア

これはAndroidスタジオとは直接関係ありません。Kotlinは内部でも外部でも同じです。のインスタンスを作成していますGson()か、それともGson静的な場合と同じですか?最初のインスタンスが必要です。
Jayson Minard、2016年

21

別のオプション(他のオプションよりもエレガントに見えるかどうかはわかりません)は、次のような呼び出しです。

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

したがって、「純粋なKotlin」の代わりにjava Arrayクラスの1つのライナーを使用しています。


2
TypeTokenは信頼できるすべての電話で機能するわけではないため、これが私にとって最良のソリューションです。純粋なコトリンを使用した簡単なワンライナー。
LuckyMalaka 2018

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

Kotlinでデータ配列を解析する方法です。


これは、受け入れられる答えであり、短くて単純なものでなければなりません。
Umar Ata

6

私は、変換するために、このようなものを使用TするstringStringバックにT使用しましたGson。正確にあなたが探しているものではなく、念のために。

拡張の宣言

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)

戻り値の型はNULL可能でなければなりません。そうでない場合、GsonライブラリのJavaコードはnullを返す可能性がありますが、Kotlinは型がnull可能ではないと想定します。その結果、KotlinでNPEを取得できます。
fdermishin

1

generic reified functionGsonのKotlin は、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
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.