繁体   English   中英

如何调用从 Kotlin 获取非空无效参数的 Java 方法?

[英]How do I call a Java method that takes a Non-null Void parameter from Kotlin?

主要问题

是否可以从 Kotlin 调用具有这样签名的 Java 方法(来自第三方库,因此无法更改方法签名)? 如果是这样,怎么做?

class Uncallable {
    void myMethod(@NonNull Void a) {
        System.out.println("Ran myMethod");
    }
}

我可以从另一个 Java class 调用这个

Uncallable u = new Uncallable();
u.myMethod(null); // IDE warns about nullability but still runs fine

但是从 Kotlin 开始,这些选项都不起作用

val u = Uncallable()
u.myMethod() // No value passed for parameter 'a'
u.myMethod(null) // Null can not be a value of a non-null type Void
u.myMethod(Unit as Void) // ClassCastException: class kotlin.Unit cannot be cast to class java.lang.Void
u.myMethod(Void)
u.myMethod(Unit)
u.myMethod(Nothing)

类似的问题(比如这个)建议制作一个 Java 接口层,让我绕过可空性规则。 这在这里有效,但我想知道是否有任何方法可以在没有这样一个额外层的情况下调用它。 我实际上不需要传递 null 值,只需调用该方法即可。

这个问题解决了类似的问题,但是他们可以控制界面并且只能使用Void? 作为类型。

我为什么要这样做?

我不是真的......但是,我有一些单元测试拦截添加到一些 Firebase 方法的addOnSuccessListener回调,并在提供的侦听器上调用onSuccess 该回调的签名使用Void作为其参数类型,以前我可以调用listener.onSuccess(null)

doAnswer { invocation ->
    val args = invocation.arguments
    @Suppress("UNCHECKED_CAST")
    val l = args[0] as OnSuccessListener<Void>
    l.onSuccess(null)
    mMockTask
}.`when`(mMockTask).addOnSuccessListener(ArgumentMatchers.any())

在最近更新 Firebase 库之后,似乎@NonNull注释已添加到onSuccess的参数中,或者 Kotlin 更改为开始执行它

public interface OnSuccessListener<TResult> {
    void onSuccess(@NonNull TResult var1);
}

结果,我无法再调用listener.onSuccess(null) - 我收到关于 null 被传递给非空参数的构建错误。

我可以制作一个VoidCaller Java 接口来解决这个问题,

public class VoidCaller {
    static void callSuccessCallback(OnSuccessListener<Void> callback) {
        callback.onSuccess(null);
    }

    static void callFailureCallback(OnFailureListener callback) {
        callback.onFailure(null);
    }
}

哪个有效,但前提是我将回调从

fileRef.delete().addOnSuccessListener { onSuccess() }

fileRef.delete().addOnSuccessListener { _ : Void? -> onSuccess() }

或者我尝试将it设置为 null 时出现错误。

Parameter specified as non-null is null: method com.app.firebaseHelper.deleteImage$lambda-11$lambda-10, parameter it

理想情况下,我想找到一种直接从 Kotlin 调用这种方法的方法。

如果你只想传递 Void object,但它的构造函数是私有的,你可以使用反射。

Constructor<Void> c = Void.class.getDeclaredConstructor();
c.setAccessible(true);
Void v = c.newInstance();

那么你可以通过它。

另一种方法是覆盖 class 或调整使用该参数的方法。 但我觉得无论如何使用 Void 参数都很奇怪。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM