Crash
HAHH9527 opened this issue · 0 comments
HAHH9527 commented
I read readme Response body types (e.g., Call<User>) and @Body types (e.g., @Body user: User) will now use the supplied serializer.
can use Call.
But I use retrofit2.Call
and Call.await()
get response crash.
And I use retrofit2.Response
no crash.
Log
Caused by: kotlinx.serialization.json.internal.JsonDecodingException: Polymorphic serializer was not found for missing class discriminator ('null')
JSON input: {"code":0,"message":null,"data":"888888"}
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:24)
at kotlinx.serialization.json.internal.JsonExceptionsKt.JsonDecodingException(JsonExceptions.kt:32)
at kotlinx.serialization.json.internal.PolymorphicKt.throwSerializerNotFound(Polymorphic.kt:76)
at kotlinx.serialization.json.internal.PolymorphicKt.decodeSerializableValuePolymorphic(Polymorphic.kt:66)
at kotlinx.serialization.json.internal.StreamingJsonDecoder.decodeSerializableValue(StreamingJsonDecoder.kt:36)
at kotlinx.serialization.json.Json.decodeFromString(Json.kt:100)
at com.jakewharton.retrofit2.converter.kotlinx.serialization.Serializer$FromString.fromResponseBody(Serializer.kt:30)
at com.jakewharton.retrofit2.converter.kotlinx.serialization.DeserializationStrategyConverter.convert(DeserializationStrategyConverter.kt:11)
at com.jakewharton.retrofit2.converter.kotlinx.serialization.DeserializationStrategyConverter.convert(DeserializationStrategyConverter.kt:7)
at retrofit2.OkHttpCall.parseResponse(OkHttpCall.java:243)
at retrofit2.OkHttpCall$1.onResponse(OkHttpCall.java:153)
at okhttp3.internal.connection.RealCall$AsyncCall.run(RealCall.kt:519)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:920)
--> GET http://****/login?mobile=13900000000
--> END GET
<-- 200 OK http://****/login?mobile=13900000000 (58ms)
Date: Fri, 06 May 2022 07:53:30 GMT
Content-Type: application/json
Transfer-Encoding: chunked
Connection: keep-alive
Vary: Origin
{"code":0,"message":null,"data":"888888"}
<-- END HTTP (41-byte body)
Code
import com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory
import kotlinx.serialization.json.Json
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import retrofit2.Retrofit
object RetrofitClient {
private fun defaultOkHttpClient(): OkHttpClient {
return OkHttpClient.Builder()
.addCommonParamInterceptor()
.addHttpLoggingInterceptor()
.build()
}
fun getRetrofit(
baseUrl: String = ServiceEnv.getEnv().baseUrl,
okHttpClient: OkHttpClient = defaultOkHttpClient()
): Retrofit {
return Retrofit.Builder()
.baseUrl(baseUrl)
.client(okHttpClient)
.addConverterFactory(json.asConverterFactory("application/json".toMediaType()))
.build()
}
val json = Json {
ignoreUnknownKeys = true
coerceInputValues = true
}
}
import kotlinx.serialization.Serializable
@Serializable
data class BaseResponse<T>(
val code: Int,
val message: String?,
val data: T,
)
import retrofit2.Call
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
interface UserService {
@GET("${ServiceEnv.usrbiz}/sms/login")
suspend fun loginGetSmsCode(@Query("mobile") mobile: String): Call<BaseResponse<String>>
}
object TestManager {
private val loginService = RetrofitClient.getRetrofit().create<UserService>()
private val successCode = intArrayOf(0, 10019, 201004)
suspend fun getSmsCode(mobile: String) = requestNetworkData {
loginService.loginGetSmsCode(mobile)
}
suspend inline fun <T> requestNetworkData(apiCall: () -> Call<BaseResponse<T>>): T {
val call = apiCall()
return call.processGetData()
}
suspend fun <T> Call<BaseResponse<T>>.processGetData(): T {
val response = await()
if (successCode.contains(response.code)) {
return response.data
} else {
throw RuntimeException("request failed")
}
}
}
How can success
import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.POST
import retrofit2.http.Query
interface UserService {
@GET("${ServiceEnv.usrbiz}/sms/login")
suspend fun loginGetSmsCodeResponse(@Query("mobile") mobile: String): Response<BaseResponse<String>>
}
import retrofit2.Response
import retrofit2.create
object TestManager {
private val loginService = RetrofitClient.getRetrofit().create<UserService>()
private val successCode = intArrayOf(0, 10019, 201004)
suspend fun getSmsCodeResponse(mobile: String) = requestNetworkDataResponse {
loginService.loginGetSmsCodeResponse(mobile)
}
suspend inline fun <T> requestNetworkDataResponse(getResponse: () -> Response<BaseResponse<T>>): T {
val body = getResponse().body()
return if (body != null && successCode.contains(body.code)) body.data
else throw RuntimeException("request failed")
}
}