Consider the following minimal Kotlin example:
fun <U> someWrapper(supplier: () -> U): () -> (U) {
return { supplier() }
}
fun foo(taskExecutor: TaskExecutor): Int {
val future = CompletableFuture.supplyAsync(someWrapper {
42
}, taskExecutor::execute)
return future.join()
}
@Test
public void shouldFoo() {
assertThat(foo(), is(42));
}
I have branch coverage rules in Jacoco, which fail for the code above, saying 1 of 2 branches is not covered on the line of the someWrapper
call. Unfortunately, it is not an option for me to exclude all classes from which someWrapper
is called.
Looking at the decompiled Java code:
public final int foo(TaskExecutor taskExecutor) {
Object var10000 = WrappersKt.someWrapper((Function0)null.INSTANCE);
if (var10000 != null) {
Object var2 = var10000;
var10000 = new Foo$sam$java_util_function_Supplier$0((Function0)var2);
}
Supplier var3 = (Supplier)var10000;
Function1 var4 = (Function1)(new Function1(this.taskExecutor) {
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object var1) {
this.invoke((Runnable)var1);
return Unit.INSTANCE;
}
public final void invoke(Runnable p1) {
((TaskExecutor)this.receiver).execute(p1);
}
public final KDeclarationContainer getOwner() {
return Reflection.getOrCreateKotlinClass(TaskExecutor.class);
}
public final String getName() {
return "execute";
}
public final String getSignature() {
return "execute(Ljava/lang/Runnable;)V";
}
});
CompletableFuture future = CompletableFuture.supplyAsync(var3, (Executor)(new Foo$sam$java_util_concurrent_Executor$0(var4)));
var10000 = future.join();
Intrinsics.checkExpressionValueIsNotNull(var10000, "future.join()");
return ((Number)var10000).intValue();
}
I think, the problem is the if (var10000 != null)
branch, which is even marked by the IDE to be unnecessary (always true).
Is it somehow possible to adjust the code such that it is possible to cover all branches, eg. by making sure the compiler does not generate that extra null check? I can change the code of both foo(..)
and someWrapper(..)
as long as I am able to supply a decorated lambda.
I use Kotlin 1.3.50 and Jacoco 0.8.4.
EDIT.
One obvious workaround is to extract supplyAsync(someWrapper { ... })
to some utils class and exclude that class only, ie.:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
This would be good enough for me, though I am still curious why the branch is added by Kotlin, where no branch need to be.
Kotlin has a safe call operator (?.) to handle null references. This operator executes any action only when the reference has a non-null value. Otherwise, it returns a null value. The safe call operator combines a null check along with a method call in a single expression.
You can use the "?. let" operator in Kotlin to check if the value of a variable is NULL. It can only be used when we are sure that we are refereeing to a non-NULL able value.
Kotlin neither allows null values to be passed as parameter values nor allows null object references unless you specify that a variable can be null . In other words, Kotlin makes you tell the compiler "this (or that) variable can be null ." Such variables are referred to as nullable values.
The basic difference while using ?. and !! is if you want to separate a normal flow of var property having a 'non-null' value with 'null' value flow use ?. But if you are sure that the var property value is not null use !!
If the return value of someWrapper
is only meant to be used as an instance of Supplier
, then you can remove the unnecessary null check by explicitly using Supplier
as the return type.
fun <U> someWrapper(supplier: () -> U): Supplier<U> {
return Supplier { supplier() }
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With