Reputation: 21
I write a piece of code, then compile it with no errors. but when I run, it throws an exception (java.lang.NoClassDefFoundError: TesKt$test$1$1).
Is this a language bug?
private fun test(block:()->Unit) = arrayOf(1).map {
object {
fun print() {
println("Hello print")
block()
}
}
}
fun main(args: Array<String>) {
val array = test{println("Hello main")}
array[0].print()
}
Upvotes: 2
Views: 393
Reputation: 2300
I'm going to conclude that it's a bug in the Kotlin compiler. I played a lot with this code and looked into the compiled bytecode. It seems the compiler is losing some information about the anonymous class which is defined by object
.
If we add a type to that object, then it works fine:
interface Printable {
fun print()
}
private fun test(block:()->Unit): List<Printable> {
return arrayOf(1).map {
object: Printable {
override fun print() {
println("Hello print")
block()
}
}
}
}
fun main(args: Array<String>) {
val array = test{println("Hello main")}
array[0].print()
}
As you can see, I only defined a simple Printable
interface and annotated the anonymous class with this interface.
Let's call your code: version A
, and this code of mine: Version B
.
I compiled code A
and then decompiled it to Java
. Here's the result:
import TestKt.test.1.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000#\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\b\u0002\n\u0002\u0018\u0002*\u0001\b\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "TestKt$test$1$1", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<1> test(Function0<Unit> block) {
Object[] $this$map$iv = new Integer[]{1};
int $i$f$map = false;
Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
int $i$f$mapTo = false;
Integer[] var6 = $this$map$iv;
int var7 = $this$map$iv.length;
for(int var8 = 0; var8 < var7; ++var8) {
Object item$iv$iv = var6[var8];
int it = ((Number)item$iv$iv).intValue();
int var11 = false;
/*#31:*/ TestKt.test..inlined.map.lambda.1 var13 = new TestKt.test..inlined.map.lambda.1(block);
destination$iv$iv.add(var13);
}
return (List)destination$iv$iv;
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((1)array.get(0)).print();
}
}
And this is the result of the same process for code B
:
import TestKt.test..inlined.map.lambda.1;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
@Metadata(
mv = {1, 1, 15},
bv = {1, 0, 3},
k = 2,
d1 = {"\u0000\"\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0011\n\u0002\u0010\u000e\n\u0002\b\u0002\n\u0002\u0010 \n\u0002\u0018\u0002\n\u0000\n\u0002\u0018\u0002\u001a\u0019\u0010\u0000\u001a\u00020\u00012\f\u0010\u0002\u001a\b\u0012\u0004\u0012\u00020\u00040\u0003¢\u0006\u0002\u0010\u0005\u001a\u001c\u0010\u0006\u001a\b\u0012\u0004\u0012\u00020\b0\u00072\f\u0010\t\u001a\b\u0012\u0004\u0012\u00020\u00010\nH\u0002"},
d2 = {"main", "", "args", "", "", "([Ljava/lang/String;)V", "test", "", "LPrintable;", "block", "Lkotlin/Function0;"}
)
public final class TestKt {
/*#19:*/private static final List<Printable> test(Function0<Unit> block) {
Object[] $this$map$iv = new Integer[]{1};
int $i$f$map = false;
Collection destination$iv$iv = (Collection)(new ArrayList($this$map$iv.length));
int $i$f$mapTo = false;
Integer[] var6 = $this$map$iv;
int var7 = $this$map$iv.length;
for(int var8 = 0; var8 < var7; ++var8) {
Object item$iv$iv = var6[var8];
int it = ((Number)item$iv$iv).intValue();
int var11 = false;
/*#31:*/ 1 var13 = new 1(block);
destination$iv$iv.add(var13);
}
return (List)destination$iv$iv;
}
public static final void main(@NotNull String[] args) {
Intrinsics.checkParameterIsNotNull(args, "args");
List array = test((Function0)TestKt.main.array.1.INSTANCE);
/*#41:*/((Printable)array.get(0)).print();
}
}
As you can see, the only differences are in the first line, as well as line numbers 19, 31 and 41 (commented like #19:
and so on).
In code A
a type (strangely) with the name of 1
is expected. But this type 1
, which is packaged as TestKt.test.1.1
, is not found and so you got your error (NoClassDefFoundError: TesKt$test$1$1
).
Inn code B
, however, a more clear type of Printable
is expected and found.
If the compiler had compiled the very first line of code A
just like code B
(import TestKt.test..inlined.map.lambda.1;
instead of import TestKt.test.1.1;
) then your code would have worked.
Upvotes: 2