Модифицируйте CallAdapter для приостановки функций, который возвращает для каждого List <Object>a List <LinkedTreeMap>. Как это решить? - PullRequest
0 голосов
/ 17 октября 2019

Я был вдохновлен написанием этого адаптера для ответа Валерия Каткова answer

Мой адаптер вызовов Retrofit способен правильно преобразовывать JSON нормальных объектов, но когда я ожидаю отпозвоните List<Object>, дооснащение вернет мне List<LinkedTreeMap>. Он не может проанализировать Object в списке

Исключение

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to com.example.networkcalladapter.Post

Фабрика CallAdapter и CallAdapter

class NetworkCallAdapterFactory : CallAdapter.Factory() {
    override fun get(
        returnType: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ) = when (getRawType(returnType)) {
        Call::class.java -> {
            val callType = getParameterUpperBound(0, returnType as ParameterizedType)
            when (getRawType(callType)) {
                ResponseNetwork::class.java -> {
                    require(callType is ParameterizedType){ "resource must be paramterized" }
                    val resultType = getParameterUpperBound(0, callType)
                    ResponseNetworkAdapter<Any>(getRawType(resultType))
                }
                else -> null
            }
        }
        else -> null
    }

}

class ResponseNetworkAdapter<T: Any>(
    private val type: Type
) : CallAdapter<T, Call<ResponseNetwork<T>>> {
    override fun responseType() = type
    override fun adapt(call: Call<T>): Call<ResponseNetwork<T>> = ResponseNetworkCall(call)
}


abstract class CallDelegate<TIn, TOut>(
    protected val proxy: Call<TIn>
) : Call<TOut> {
    override fun execute(): Response<TOut> = throw NotImplementedError()
    final override fun enqueue(callback: Callback<TOut>) = enqueueImpl(callback)
    final override fun clone(): Call<TOut> = cloneImpl()

    override fun cancel() = proxy.cancel()
    override fun request(): Request = proxy.request()
    override fun isExecuted() = proxy.isExecuted
    override fun isCanceled() = proxy.isCanceled

    abstract fun enqueueImpl(callback: Callback<TOut>)
    abstract fun cloneImpl(): Call<TOut>
}


class ResponseNetworkCall<T: Any>(proxy: Call<T>) : CallDelegate<T, ResponseNetwork<T>>(proxy) {

    override fun enqueueImpl(callback: Callback<ResponseNetwork<T>>) {

        proxy.enqueue(object : Callback<T> {

            override fun onResponse(call: Call<T>, response: Response<T>) {
                callback.onResponse(this@ResponseNetworkCall, Response.success(ResponseNetwork.create(response)))
            }

            override fun onFailure(call: Call<T>, t: Throwable) {
                callback.onResponse(this@ResponseNetworkCall, Response.success(ResponseNetwork.create(Exception(t))))
            }
        })
    }

    override fun cloneImpl() = ResponseNetworkCall(proxy.clone())
}

ResponseNetwork

sealed class ResponseNetwork<T> {

    companion object {

        fun <T> create(error: Exception): ResponseNetworkError<T> {
            return ResponseNetworkError(error)
        }

        fun <T> create(response: Response<T>): ResponseNetwork<T> {
            return if (response.isSuccessful) {
                response.body()?.let {
                    ResponseNetworkSuccess(response.code(), response.headers(), it)
                } ?: ResponseNetworkEmpty(
                    response.code(),
                    response.errorBody()?.string() ?: "unknown error"
                )
            } else {
                val msg = response.errorBody()?.string()
                ResponseNetworkError(Exception(msg))
            }
        }

    }
}

data class ResponseNetworkSuccess<T>(
    val code: Int,
    val header: Headers,
    val body: T
) : ResponseNetwork<T>()

data class ResponseNetworkEmpty<T>(
    val code: Int,
    val message: String
) : ResponseNetwork<T>()

data class ResponseNetworkError<T>(
    val exception: Exception
) : ResponseNetwork<T>()

Удаленный API

@GET("posts")
    suspend fun getPost(): ResponseNetwork<List<Post>>

Модификация

Retrofit.Builder()
        .baseUrl("https://jsonplaceholder.typicode.com/")
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(NetworkCallAdapterFactory())
        .build()
        .create(RemoteApi::class.java)

Пост-модель

data class Post(val userId: Int,
                val id: Int,
                val title: String,
                val body: String)

Кто-то понимает, почему модернизация всегда возвращается ко мне List<LinkedTreeMap> всякий раз, когда мне нужен список из сети?

Ответы [ 2 ]

0 голосов
/ 25 октября 2019

Я исправил ошибку в NetworkCallAdapterFactory

ResponseNetworkAdapter<Any>((resultType))

0 голосов
/ 18 октября 2019

Вы можете заменить свой удаленный API этим и проверить его.

@GET("posts")
suspend fun getPost(): Deferred<Response<ResponseNetwork<List<Post>>>
...