Невозможно переписать класс Java с параметрами типа в Kotlin - PullRequest
0 голосов
/ 01 ноября 2019

Мне показалось, что я достаточно хорошо понимаю модификаторы in, out и * от Kotlin, но я не могу переписать один класс с 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"

1 Ответ

1 голос
/ 02 ноября 2019

Поскольку вы хотите получить в качестве входных данных ModelValidator для каждого универсального типа, вы можете использовать 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)
            }
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...