Converted java class file to kotlin makes compilat

2019-07-07 01:29发布

问题:

I have a java class file which works fine, but if I convert it to Kotlin it makes some problem. Here is a Java version

 public class CallbackWrapper<T> implements Callback<T> {
   private Wrapper<T> wrapper;

   public CallbackWrapper(Wrapper<T> wrapper) {
      this.wrapper = wrapper;
   }

   public void onFailure(Call<T> call, Throwable t) {
      wrapper.onResult(t, null);
   }

   public void onResponse(Call<T> call, Response<T> response) {
      wrapper.onResult(null, response);
   }

   public interface Wrapper<T> {
      void onResult(@Nullable Throwable t, @Nullable Response<T> response);
   }
}

And this is how I'm using this class without any problem...

request.enqueue(CallbackWrapper<RegisterResponse> { throwable, response ->
     response?.let { callBack.onResponse(response.body() ?: RegisterResponse()) }
     throwable?.let { callBack.onFailed(throwable.message!!) }
 })

And here is Kotlin version after converting

class CallbackWrapper<T>(private val wrapper: CallbackWrapper.Wrapper<T>) : Callback<T> {

    override fun onFailure(call: Call<T>, t: Throwable) {
        wrapper.onResult(t, null)
    }

    override fun onResponse(call: Call<T>, response: Response<T>) {
        wrapper.onResult(null, response)
    }

    interface Wrapper<T> {
        fun onResult(t: Throwable?, response: Response<T>?)
    }
}

The problem is that after converting it to Kotlin, code block where I'm using this class were not working. I don't understand what is the difference between them.

Here is compile error log

Error:(17, 63) Type mismatch: inferred type is (???, ???) -> [ERROR :<ERROR FUNCTION RETURN TYPE>] but CallbackWrapper.Wrapper<RegisterResponse> was expected
Error:(17, 65) Cannot infer a type for this parameter. Please specify it explicitly.
Error:(17, 76) Cannot infer a type for this parameter. Please specify it explicitly.

回答1:

You have two issues with your code, as far as I can tell.

First is that Kotlin doesn't allow using lambdas to implement Kotlin functional interfaces, so your lambda isn't going to work (it does allow implementing Java functional interfaces, because Java doesn't have proper function types). So to call the code unchanged, you want to use object notation instead:

request.enqueue(CallbackWrapper<RegisterResponse>(object : CallbackWrapper.Wrapper<RegisterResponse> {
        override fun onResult(throwable: Throwable?, response: Response<RegisterResponse>?) {
            response?.let { callBack.onResponse(response.body() ?: RegisterResponse()) }
            throwable?.let { callBack.onFailure(throwable.message!!) }
        }
    }))

You can declare your CallbackWrapper class differently if you prefer using lambdas:

typealias Wrapper<T> = (t: Throwable?, response: Response<T>?) -> Unit
class OtherCallbackWrapper<T>(val wrapper: Wrapper<T>) : Callback<T> {
    override fun onFailure(call: Call<T>, t: Throwable) = wrapper.invoke(t, null)
    override fun onResponse(call: Call<T>, response: Response<T>) = wrapper.invoke(null, response)
}

So that's the but CallbackWrapper.Wrapper<RegisterResponse> was expected part taken care of.

This still won't work, though, which brings us to the reason the first half of the error message is inferred type is (???, ???) -> [ERROR :<ERROR FUNCTION RETURN TYPE>]. That's basically type inference failing. The calls to callBack don't quite seem to match the CallBack interface implied by CallbackWrapper, which I expect might have something to do with it.

EDIT:

Added an answer to your Retrofit question with a more concise solution.



标签: java kotlin