首页 > 解决方案 > 无法将具有类型参数的 Java 类重写为 Kotlin

问题描述

我以为我对 Kotlin 的in,out*修饰符有很好的理解,但我无法将一个类从 Java 重写为 Kotlin。也许有人可以帮助我。在我的应用程序中,我正在使用改造,并且在我的所有项目中,我都有这个 ApiResponseValidatorJava 类,它负责验证 API 响应模型,例如 Customer。用 Kotlin 编写的这个类看起来如何?

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;

import okhttp3.ResponseBody;
import retrofit2.Converter;
import retrofit2.Retrofit;

public class ApiResponseValidatorJava extends Converter.Factory {

    private HashMap<Type, ModelValidator> validators = new HashMap();

    public ApiResponseValidatorJava(ModelValidator... validators) {
        for (ModelValidator v : validators) {
            this.validators.put(v.getModelType(), v);
        }
    }

    @Override
    public Converter<ResponseBody, ?> responseBodyConverter(final Type type, Annotation[] annotations, Retrofit retrofit) {
        final Converter<ResponseBody, Object> mainConverter = retrofit.nextResponseBodyConverter(this, type, annotations);
        return new Converter<ResponseBody, Object>() {
            @Override
            public Object convert(ResponseBody value) throws IOException {
                Object apiResponseModel = mainConverter.convert(value);
                if (validators.containsKey(type)) {
                    validators.get(type).validate(apiResponseModel);
                }
                return apiResponseModel;
            }
        };
    }
}

import java.lang.reflect.Type

interface ModelValidator<T> {
    fun getModelType(): Type
    fun validate(data: T)
}
import retrofit2.Call
import retrofit2.http.*

interface Api {
    @GET("api/session/customer")
    fun getCustomer(): Call<Customer>
}
import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass

@JsonClass(generateAdapter = true)
data class Customer(
    @Json(name = "id")
    val id: String,
    @Json(name = "phone")
    val phone: String
)
class CustomerResponseValidator : ModelValidator<Customer> {
    override fun getModelType() = Customer::class.java

    override fun validate(customer: Customer) {
        if (!customer.phone.startsWith("+212")) {
            throw IllegalAccessException("Phone doesn't start with +212")
        }
    }
}

import android.os.Bundle
import androidx.appcompat.app.AppCompatActivity
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
    }

    private fun buildRetrofit(): Api {
        val apiResponseValidator = ApiResponseValidatorJava(
            CustomerResponseValidator()
        )

        return Retrofit.Builder()
            .baseUrl("https://example.com/")
            .client(OkHttpClient.Builder().build())
            .addConverterFactory(apiResponseValidator)
            .addConverterFactory(MoshiConverterFactory.create())
            .build()
            .create(Api::class.java)
    }

}
// gradle dependecies
implementation group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.6.2'
implementation group: 'com.squareup.retrofit2', name: 'converter-moshi', version: '2.6.2'
implementation group: 'com.squareup.moshi', name: 'moshi', version: '1.8.0'
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.8.0"

标签: javaandroidgenericskotlin

解决方案


由于您希望接收ModelValidator每个泛型类型的输入 a,您可以使用ModelValidator<out Any?>.

你可以使用这样的东西:

class ApiResponseValidatorJava(vararg validators: ModelValidator<out Any?>) : Converter.Factory() {

    private val validators = mutableMapOf<Type, ModelValidator<Any?>>().apply {
        validators.forEach {
            @Suppress("UNCHECKED_CAST")
            this[it.getModelType()] = it as ModelValidator<Any?>
        }
    }

    override fun responseBodyConverter(
        type: Type,
        annotations: Array<Annotation>,
        retrofit: Retrofit
    ): Converter<ResponseBody, *> {
        val mainConverter = retrofit.nextResponseBodyConverter<Any?>(this, type, annotations)
        return Converter<ResponseBody, Any?> { value ->
            mainConverter.convert(value).also { apiResponseModel ->
                validators[type]?.validate(apiResponseModel)
            }
        }
    }
}

推荐阅读