Wie bereits erwähnt von @ Miha_x64, Retrofit nicht weiß, über Ihre Klassen (MyClass1
und MyClass2
), weil Ihr Call
verwendet die Any
Typ. Retrofit erstellt daher keine Instanz von MyClass1
oder MyClass2
, sondern erstellt lediglich eine Instanz der Klasse Any
.
Die einfachste Lösung wäre, nur die beiden Klassen kombinieren:
data class MyClass(
val id: String?,
val data: String?,
val token: String?,
val url: String?,
val quantity: Int
)
Dann können Sie den Antworttyp in Ihrer Schnittstelle angeben:
@FormUrlEncoded
@POST("payments/events/{id}")
fun postPayment(@Path("id") id: String): Call<MyClass>
Im Fall Ihre Antwort nicht hat id
oder data
Element werden sie nur null
sein. Dann können Sie überprüfen, welche Art von Antwort empfangen wurde einfach durch Überprüfung, welche Werte null
:
if (response.body().id != null) {
// Handle type 1 response...
} else if (response.body().token != null) {
// Handle type 2 response...
}
Eine etwas komplexere Lösung wäre, einen Wrapper für Ihre zwei Klassen zu schreiben, und eine Art Adapter zum Auffüllen die Verpackung. Dies würde die NULL-Zulässigkeit jedes der Felder vermeiden und Ihre Datenstruktur getrennt halten.
Dies ist die basierend auf ConverterFactory
Sie verwenden, aber wenn zum Beispiel unterscheiden würden Sie Gson verwenden, würde es in etwa so aussehen:
data class ApiResponse(
val val1: MyClass1? = null,
val val2: MyClass2? = null
)
class ApiResponseAdapter : TypeAdapter<ApiResponse> {
@Throws(IOException::class)
override fun write(out: JsonWriter, value: ApiResponse?) {
if (value != null) {
out.beginObject()
value.val1?.id? let { out.name("id").value(it) }
value.val1?.data? let { out.name("data").value(it) }
value.val2?.token? let { out.name("token").value(it) }
value.val2?.url? let { out.name("url").value(it) }
value.val2?.quantity? let { out.name("quantity").value(it) }
out.endObject()
} else {
out.nullValue()
}
}
@Throws(IOException::class)
override fun read(in: JsonReader): ApiResponse {
reader.beginObject()
var id: String? = null
var data: String? = null
var token: String? = null
var url: String? = null
var quantity: Int = 0
while(in.hasNext()) {
val name = in.nextName()
if (name.equals("id", true)) {
id = in.nextString()
} else if (name.equals("data", true)) {
data = in.nextString()
} else if (name.equals("token", true)) {
token = in.nextString()
} else if (name.equals("url", true)) {
url = in.nextString()
} else if (name.equals("quantity", true)) {
quantity = in.nextInt()
}
}
reader.endObject()
if (id != null && data != null) {
return ApiResponse(MyClass1(id, data), null)
} else if (token != null && url != null) {
return ApiResponse(null, MyClass2(token, url, quantity))
} else {
return ApiResponse()
}
}
}
Dann können Sie diese Art Adapter an Ihren Gson Instanz hinzufügen :
val gson = GsonBuilder().registerTypeAdapter(ApiResponse::class.java, ApiResponseAdapter()).create()
den Typ Call<Any>
mit Call<ApiRepsone>
ersetzen dann können und Sie dann überprüfen, welche Antwort von Prüfung empfangen wurde, der Wert null
ist:
if (response.body().val1 != null) {
// Handle MyClass1 response...
} else if (response.body().val2 != null) {
// Handle MyClass2 response...
}
Warum verwenden Sie kein benutzerdefiniertes Objekt für den Empfang Ihrer Antwort? etwas wie 'Call' –
Marce
Wie ich beschrieben, in meinem Fall kann der Antworttyp mehrere Typen sein - MyClass1 oder MyClass2. – Igor
Gibt es ('MyClass1' und' MyClass2') zu viele Unterschiede? – Marce