まずは結果から話しましょう
Solon フレームワークに変更した後、All in kt で問題が発生しました。つまり、JSON データ レベルが深い場合、最初のレイヤーのみをシリアル化できます。これは、テスト済みの主流の JSON フレームワークの場合です。1 日かけて調査した結果、依存しない解決策をついに見つけました。まず結果コード:
@OptIn(ExperimentalStdlibApi::class)
fun main(args: Array<String>) {
val ret = """{"code":200,"msg":"成功","data":{"id":"out123","name":"outName","inner":{"id":"inner123","name":"innerName","innerdata":["1","2","3"]}}}"""
// inner解析结果 snack3: false | fastJson2: false | gson: false
val snack3 = ONode.deserialize<Ret<Out>>(ret,Ret<Out>()::class.java)
val fastJson2 = JSON.parseObject<Ret<Out>>(ret, Ret<Out>()::class.java)
val gson = Gson().fromJson<Ret<Out>>(ret, Ret<Out>()::class.java)
// inner解析结果 snack3: true | fastJson2: true | gson: true
val typeOf_T = typeOf<Ret<Out>>().javaType
val typeOf_snack3 = ONode.deserialize<Ret<Out>>(ret,typeOf_T)
val typeOf_fastJson2 = JSON.parseObject<Ret<Out>>(ret, typeOf_T)
val typeOf_gson = Gson().fromJson<Ret<Out>>(ret, typeOf_T)
}
data class Ret<T>(
var code:String?=null,
var msg:String?=null,
var data:T?=null
)
data class Out(
var id:String?=null,
var name:String?=null,
var inner:Inner?=null
)
data class Inner(
var id:String?=null,
var name:String?=null,
var innerdata:List<String>?=null
)
typeOf<T>().javaType
逆シリアル化に渡される Type パラメーターを使用します。ただし、このメソッドを使用するには、呼び出し側メソッドに追加する必要があります。@OptIn(ExperimentalStdlibApi::class)
詳細について話しましょう
データ クラスは確かに便利ですが、kt の設計思想により、データ クラスは最終クラスにコンパイルされます。つまり、このデータ型は継承できません。このため、上記の問題が発生し、基本的に、匿名内部クラスを使用してジェネリックスを渡す公式の方法は使用できません。
// 取自snack3文档
List<UserModel> list = ONode.deserialize(json, (new ArrayList<UserModel>(){}).getClass());
Kt は、これと同様の匿名内部クラスを実装するobject:
ために使用
val list: List<UserModel> = ONode.deserialize<List<UserModel>>(json, object : ArrayList<UserModel>() {}.javaClass)
公式の方法だとopen class
結果を受け取るクラスを変更する必要があり、最上位層だけを変更しているのですが、書き方としては少し変で、結局そこには空のクラスが表示されています。したがって、一般的な結果クラスとデータ クラスの両方が必要な場合は、パス タイプdata class
を使用するのが最善です。typeOf<T>().javaType
別の方法があります
Solon フレームワークが kt で直接使用できることを知らなかったため.javaType
、フレームワークはデフォルトで Snack3 を使用します。したがって、TypeRef
メソッドは kt の一般的な実現原理を使用してカプセル化されます。
inline fun <reified T> gType(): Type? {
return object : TypeRef<T>() {}.type
}
トップレベル関数として宣言されている場合は、関数を呼び出すだけです。
val ret= ONode.deserialize<Ret<Out>>(ret,gType<Ret<Out>>())
このメソッドは基本的に匿名の内部クラスを使用しますが、内部クラスが宣言されている場所は、少なくともコードが呼び出しを表示する場所には表示されません。TypeRef
ただし、このメソッドはSnack3 によって提供され、 GSON で呼び出されるように見えるシリアル化フレームワークに依存していますTypeToken
。この方法が気に入った場合は、自分でカプセル化することもできます。