2017-12-22 5 views
5

Ich erhalte ein JSON-Datenmodell mit einem Map-Wrapper Tabelle. Ich versuche, Generics zu verwenden, um den Typ zu übergeben, der jenseits des Wrappers ist, aber es wird zur Laufzeit nicht gut übersetzt. Hier ist ein Beispiel für meine JSON-Datei:Kotlin Gson Deserializing

{ 
"Table": [ 
{ 
    "paymentmethod_id": 1, 
    "paymentmethod_description": "Cash", 
    "paymentmethod_code": "Cash", 
    "paymentmethod_is_ach_onfile": false, 
    "paymentmethod_is_element": false, 
    "paymentmethod_is_reward": false, 
    "paymentmethod_is_openedgeswipe": false, 
    "paymentmethod_update_user_id": 1, 
    "paymentmethod_insert_user_id": 1, 
    "paymentmethod_insertdate": "2014-10-07 14:53:16", 
    "paymentmethod_deleted": false, 
    "paymentmethod_is_mobile_visible": true 
    } 
    ] 
} 

Die Wrapperklasse, die ich verwende, heißt Tabelle.

data class Table<T>(
    @SerializedName("Table") val models : Array<T> 
) 

Die eigentliche Modellklasse ist PaymentMethod.

data class PaymentMethod(
    @SerializedName("paymentmethod_id") val idNumber : Int = -1 
) 

Ich habe eine generische Datenmanager-Klasse erstellt, die < T> Typ nimmt. Ich denke Verwendung Subklassen der Datenmanager die Eingabe und Ergebnisse (wie erklärt die Modellklasse Paymentmethod zu lokalisieren.

open class NXDataManager<T>(manager: NXNetworkManager? = null, rpc : String?, parameters: List<Pair<String, String>>? = null, method : String = "get") 
{ 
    ... 


open fun sendRequest(completionHandler: (models:Array<T>) -> Unit, errorHandler: (error:FuelError) -> Unit) { 

    val request = NXNetworkRequest(rpc, parameters, method) 

    request.send(manager, completionHandler = { s: String -> 

     val table: Table<T> = Gson().fromJson(s) 

     completionHandler(table.models) 

    }, errorHandler = errorHandler) 
} 

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

} 

Mein Unterklasse Datenmanager das Modell in zu analysieren gibt.

final public class PaymentMethodsDataManager : NXDataManager<PaymentMethod> 
{ 
    constructor() : super("genGetPaymentMethods") 

} 

wenn ich den Code ausführen wie:

val table: Table<T> = Gson().fromJson(s) 

erhalte ich eine Fehlermeldung java.lang.ClassCastExceptio n: java.lang.Object [] kann nicht in Networking.PaymentMethod [] umgewandelt werden. Allerdings, wenn ich in einem expliziten Typ passieren funktioniert es wie erwartet - das Array in Paymentmethod Modelle Parsen:

val table: Table<PaymentMethod> = Gson().fromJson(s) 

Irgendwelche Ideen, wie ich immer noch den generischen Typ T verwenden kann?

Antwort

4

Datenklasse:

data class Table<T>(
    @SerializedName("Table") val models : Array<T> 
) 

zu JSON:

val gson = Gson() 
val json = gson.toJson(table) 

von JSON:

val json = getJson() 
val table = gson.fromJson(json, Table::class.java) 
+0

ich nicht in der Lage war Tabelle :: class.java zu verwenden, da Tabellen seines generischen Typ Tabelle :: class.java angeben muss. Aber das wirft einen Fehler, weil ich vermute, dass der Compiler nicht sagen kann, was T zur Kompilierzeit ist (ist das überhaupt nicht der Punkt von Generika?). –

3

Methode fromJson ist generisch, so dass, wenn Sie es für Table<T> Variable nennen es schafft Array<Any> als am besten geeignet. Sie müssen beachten, dass PaymentMethod Klasse erweitert T generisch ist, aber ich weiß nicht, ob es überhaupt möglich ist. Wenn Sie herausfinden, wie es zu machen, verwenden Sie so etwas wie folgt vor:

val table: Table<T> = Gson().fromJson<Table<PaymentMethod>>(s) 

In Ihrem Fall ich Gson Adapter bin mit.Nach Funktion erstellt Objekt mit dem angegebenen type Parameter:

fun getObjectFromString(type: Type, string: String) = 
    Gson().getAdapter(TypeToken.get(type)).fromJson(string) 

es nutzen zu können, schreiben Sie etwas folgendes:

val table: Table<T> = getObjectFromString(Table<PaymentMethod>::class.java, s) as Table<PaymentMethod> 

aktualisieren

Um Ersatz Klasse Guss vermeiden können Sie reified generische Funktion verwenden:

inline fun <reified T> getObjectFromString(string: String): T = 
      getGsonConverter().getAdapter(TypeToken.get(T::class.java)).fromJson(string)!! 

In diesem Fall verwenden wäre einfacher:

val table: Table<T> = getObjectFromString<Table<PaymentMethod>>(s) 

Ich verwendete erste Lösung in Fällen, in denen ich nicht weiß, was das Objekt geben würde - ich habe nur Type Variable mit Informationen über das Objekt bekam.

2

java.lang.ClassCastException: java.lang.Object [] nicht zu gegossen werden kann Networking.PaymentMethod []

Ihre JSON ist

{ 
"Table": [ 
{ 
    "paymentmethod_id": 1, 
    "paymentmethod_description": "Cash", 
    "paymentmethod_code": "Cash", 
    "paymentmethod_is_ach_onfile": false, 
    "paymentmethod_is_element": false, 
    "paymentmethod_is_reward": false, 
    "paymentmethod_is_openedgeswipe": false, 
    "paymentmethod_update_user_id": 1, 
    "paymentmethod_insert_user_id": 1, 
    "paymentmethod_insertdate": "2014-10-07 14:53:16", 
    "paymentmethod_deleted": false, 
    "paymentmethod_is_mobile_visible": true 
    } 
    ] 
} 

erstellen data class, PaymentMethod.

Wir erstellen häufig Klassen, deren Hauptzweck es ist, Daten zu speichern. In einer solchen Klasse einige Standard-Funktionalität und Utility-Funktionen sind oft mechanisch ableitbar aus den Daten .

data class PaymentMethod(@SerializedName("Table") val table:ArrayList<PaymentData>) 
data class PaymentData 

         (
         @SerializedName("paymentmethod_id") val paymentmethod_id: Int, 
         @SerializedName("paymentmethod_description") val paymentmethod_description: String, 
         @SerializedName("paymentmethod_code") val paymentmethod_code:String, 
         @SerializedName("paymentmethod_is_ach_onfile") val paidStatus:Boolean, 
         @SerializedName("paymentmethod_is_element") val paymentmethod_is_element:Boolean, 
         @SerializedName("paymentmethod_is_reward") val paymentmethod_is_reward:Boolean, 
         @SerializedName("paymentmethod_is_openedgeswipe") val paymentmethod_is_openedgeswipe:Boolean, 
         @SerializedName("paymentmethod_update_user_id") val paymentmethod_update_user_id:Int, 
         @SerializedName("paymentmethod_insert_user_id") val paymentmethod_insert_user_id:Int, 
         @SerializedName("paymentmethod_insertdate") val paymentmethod_insertdate:String, 
         @SerializedName("paymentmethod_deleted") val paymentmethod_deleted:Boolean), 
         @SerializedName("paymentmethod_is_mobile_visible") val paymentmethod_is_mobile_visible:Boolean 
         ) 

können Sie rufen auf diese Weise

val paymentDATA = Gson().fromJson<PaymentMethod>("JSON_RESPONSE", PaymentMethod::class.java) 
    val _adapterPaymentHistory = paymentDATA.table