如何调用从Kotlin获取Non-null Void参数的Java方法



主要问题

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

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

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

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

但从科特林来看,这些选项都不适用

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的规则。这在这里很有效,但我想知道是否有任何方法可以在没有额外层的情况下调用它。我实际上不需要传递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库之后,似乎要么在onSuccess的参数中添加了@NonNull注释,要么Kotlin更改为开始强制执行

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

因此,我不能再调用listener.onSuccess(null)了——我得到了一个关于为非null参数传递null的构建错误。

我能够制作一个VoidCallerJava接口来绕过这个问题,

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() }

或者我在尝试将非null类型的CCD_ 10设置为null时出错。

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

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

如果只想传递Void对象,但其构造函数是私有的,则可以使用反射。

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

然后你就可以通过了。

既然问题是关于如何从Kotlin做到这一点,这里是Kotlin版本的

fun makeVoid(): Void {
val c: Constructor<Void> = Void::class.java.getDeclaredConstructor()
c.isAccessible = true
return c.newInstance()
}

val u = Uncallable()
u.myMethod(makeVoid())

最新更新