Considere el siguiente ejemplo mínimo de Kotlin:
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));
}
Tengo reglas de cobertura de sucursales en Jacoco, que fallan para el código anterior, diciendo que 1 de 2 sucursales no está cubierta en la línea de la someWrapper
llamada. Desafortunadamente, no es una opción para mí excluir todas las clases de las que someWrapper
se llama.
Mirando el código Java descompilado:
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();
}
Creo que el problema es la if (var10000 != null)
rama, que incluso está marcada por el IDE como innecesaria (siempre cierta).
¿De alguna manera es posible ajustar el código de modo que sea posible cubrir todas las ramas, por ejemplo? ¿asegurándose de que el compilador no genera esa verificación nula adicional? Puedo cambiar el código de ambos foo(..)
y someWrapper(..)
siempre que pueda suministrar una lambda decorada.
Yo uso Kotlin 1.3.50 y Jacoco 0.8.4.
EDITAR.
Una solución obvia es extraer supplyAsync(someWrapper { ... })
a algunas clases de utilidades y excluir solo esa clase, es decir:
fun <U> supplyAsync(supplier: () -> U, executor: TaskExecutor): CompletableFuture<U> {
return CompletableFuture.supplyAsync(someWrapper { supplier() }, executor::execute)
}
Esto sería lo suficientemente bueno para mí, aunque todavía tengo curiosidad por saber por qué Kotlin agrega la rama, donde no es necesario que esté.
Type inference failed
cuando intento compilar su código de muestra. ¡Sería genial si pudiera proporcionar un código de muestra que funciona de inmediato! Por ejemplo,taskExecutor
ycontroller
son incógnitas.Respuestas:
Si el valor de retorno de
someWrapper
solo debe usarse como una instancia deSupplier
, entonces puede eliminar la verificación nula innecesaria mediante el uso explícitoSupplier
como tipo de retorno.fuente