Open
Description
Describe the bug
While setting up my navigation graph, I ran into an ExceptionInInitializerError
when trying to use @Serializable
on a data object
containing a NavDeepLink
member.
@Serializable
data object MySerializableObject {
@Transient val deepLink: NavDeepLink = navDeepLink<MySerializableObject>(basePath = "Hello World")
}
Making the member @Transient
did not help and it seems to me that the exception is caused in the generated static
initializer., i.e. here somewhere (extract from Reproduction.decompiled.java
further down):
static {
String basePath$iv = "Hello World";
Map typeMap$iv = MapsKt.emptyMap();
Function1 deepLinkBuilder$iv = (Function1)MySerializableObject$special$$inlined$navDeepLink$default$1.INSTANCE;
int $i$f$navDeepLink = false;
deepLink = NavDeepLinkDslBuilderKt.navDeepLink(basePath$iv, Reflection.getOrCreateKotlinClass(MySerializableObject.class), typeMap$iv, deepLinkBuilder$iv);
$cachedSerializer$delegate = LazyKt.lazy(LazyThreadSafetyMode.PUBLICATION, () -> {
return (KSerializer)(new ObjectSerializer("se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject", INSTANCE, new Annotation[0]));
});
$stable = 8;
}
Full Stack trace
java.lang.ExceptionInInitializerError
at se.fzy.kotlinx_serialization_plugin_bug.Reproduction.MySerializableObject#serializer is not null(Reproduction.kt:18)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.runTestClass(JUnitTestClassExecutor.java:112)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:58)
at org.gradle.api.internal.tasks.testing.junit.JUnitTestClassExecutor.execute(JUnitTestClassExecutor.java:40)
at org.gradle.api.internal.tasks.testing.junit.AbstractJUnitTestClassProcessor.processTestClass(AbstractJUnitTestClassProcessor.java:54)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.processTestClass(SuiteTestClassProcessor.java:53)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:92)
at jdk.proxy1/jdk.proxy1.$Proxy4.processTestClass(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$2.run(TestWorker.java:181)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:130)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:101)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:61)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:122)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(Unknown Source)
at java.base/java.lang.reflect.Method.invoke(Unknown Source)
at kotlinx.serialization.internal.PlatformKt.findObjectSerializer(Platform.kt:158)
at kotlinx.serialization.internal.PlatformKt.constructSerializerForGivenTypeArgs(Platform.kt:51)
at kotlinx.serialization.internal.PlatformKt.constructSerializerForGivenTypeArgs(Platform.kt:40)
at kotlinx.serialization.internal.PlatformKt.compiledSerializerImpl(Platform.kt:27)
at kotlinx.serialization.SerializersKt__SerializersKt.serializerOrNull(Serializers.kt:322)
at kotlinx.serialization.SerializersKt.serializerOrNull(Unknown Source)
at kotlinx.serialization.SerializersKt__SerializersKt.serializer(Serializers.kt:299)
at kotlinx.serialization.SerializersKt.serializer(Unknown Source)
at androidx.navigation.NavDeepLinkDslBuilder.<init>(NavDeepLinkDslBuilder.kt:99)
at androidx.navigation.NavDeepLinkDslBuilderKt.navDeepLink(NavDeepLinkDslBuilder.kt:64)
at se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject.<clinit>(Reproduction.kt:31)
... 40 more
Caused by: java.lang.NullPointerException: Cannot invoke "kotlin.Lazy.getValue()" because "se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject.$cachedSerializer$delegate" is null
at se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject.get$cachedSerializer(Reproduction.kt:22)
at se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject.serializer(Reproduction.kt:22)
... 53 more
To Reproduce
Run the Reproduction.kt
unit test in https://github.com/FelixZY/kotlinx-serialization-plugin-bug . The code introducing the issue is separated into commit 1cf8080
.
Reproduction junit test
package se.fzy.kotlinx_serialization_plugin_bug
import androidx.navigation.NavDeepLink
import androidx.navigation.navDeepLink
import kotlinx.serialization.Serializable
import kotlinx.serialization.Transient
import org.junit.Assert.assertNotNull
import org.junit.Test
class Reproduction {
@Test
fun `MySerializableObject is not null`() {
assertNotNull(MySerializableObject)
}
@Test
fun `MySerializableObject#serializer is not null`() {
assertNotNull(MySerializableObject.serializer())
}
}
@Serializable
data object MySerializableObject {
@Transient val deepLink: NavDeepLink = navDeepLink<MySerializableObject>(basePath = "Hello World")
}
Reproduction.decompiled.java
// Reproduction.java
package se.fzy.kotlinx_serialization_plugin_bug;
import androidx.compose.runtime.internal.StabilityInferred;
import kotlin.Metadata;
import org.junit.Assert;
import org.junit.Test;
@Metadata(
mv = {2, 0, 0},
k = 1,
xi = 48,
d1 = {"\u0000\u0014\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0010\u0002\n\u0002\b\u0002\u0018\u00002\u00020\u0001B\u0005¢\u0006\u0002\u0010\u0002J\b\u0010\u0003\u001a\u00020\u0004H\u0007J\b\u0010\u0005\u001a\u00020\u0004H\u0007¨\u0006\u0006"},
d2 = {"Lse/fzy/kotlinx_serialization_plugin_bug/Reproduction;", "", "()V", "MySerializableObject is not null", "", "MySerializableObject#serializer is not null", "app_debugUnitTest"}
)
@StabilityInferred(
parameters = 1
)
public final class Reproduction {
public static final int $stable;
@Test
public final void MySerializableObject_is_not_null/* $FF was: MySerializableObject is not null*/() {
Assert.assertNotNull(MySerializableObject.INSTANCE);
}
@Test
public final void MySerializableObject_serializer_is_not_null/* $FF was: MySerializableObject#serializer is not null*/() {
Assert.assertNotNull(MySerializableObject.INSTANCE.serializer());
}
}
// MySerializableObject.java
package se.fzy.kotlinx_serialization_plugin_bug;
import androidx.compose.runtime.internal.StabilityInferred;
import androidx.navigation.NavDeepLink;
import androidx.navigation.NavDeepLinkDslBuilderKt;
import java.lang.annotation.Annotation;
import java.util.Map;
import kotlin.Lazy;
import kotlin.LazyKt;
import kotlin.LazyThreadSafetyMode;
import kotlin.Metadata;
import kotlin.collections.MapsKt;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Reflection;
import kotlin.jvm.internal.SourceDebugExtension;
import kotlinx.serialization.KSerializer;
import kotlinx.serialization.Serializable;
import kotlinx.serialization.Transient;
import kotlinx.serialization.internal.ObjectSerializer;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@Serializable
@Metadata(
mv = {2, 0, 0},
k = 1,
xi = 48,
d1 = {"\u0000.\n\u0002\u0018\u0002\n\u0002\u0010\u0000\n\u0002\b\u0002\n\u0002\u0018\u0002\n\u0002\b\u0004\n\u0002\u0010\u000b\n\u0002\b\u0002\n\u0002\u0010\b\n\u0000\n\u0002\u0018\u0002\n\u0000\n\u0002\u0010\u000e\n\u0000\bÇ\n\u0018\u00002\u00020\u0001B\u0007\b\u0002¢\u0006\u0002\u0010\u0002J\u0013\u0010\b\u001a\u00020\t2\b\u0010\n\u001a\u0004\u0018\u00010\u0001HÖ\u0003J\t\u0010\u000b\u001a\u00020\fHÖ\u0001J\u000f\u0010\r\u001a\b\u0012\u0004\u0012\u00020\u00000\u000eHÆ\u0001J\t\u0010\u000f\u001a\u00020\u0010HÖ\u0001R\u001c\u0010\u0003\u001a\u00020\u00048\u0006X\u0087\u0004¢\u0006\u000e\n\u0000\u0012\u0004\b\u0005\u0010\u0002\u001a\u0004\b\u0006\u0010\u0007¨\u0006\u0011"},
d2 = {"Lse/fzy/kotlinx_serialization_plugin_bug/MySerializableObject;", "", "()V", "deepLink", "Landroidx/navigation/NavDeepLink;", "getDeepLink$annotations", "getDeepLink", "()Landroidx/navigation/NavDeepLink;", "equals", "", "other", "hashCode", "", "serializer", "Lkotlinx/serialization/KSerializer;", "toString", "", "app_debugUnitTest"}
)
@StabilityInferred(
parameters = 0
)
@SourceDebugExtension({"SMAP\nReproduction.kt\nKotlin\n*S Kotlin\n*F\n+ 1 Reproduction.kt\nse/fzy/kotlinx_serialization_plugin_bug/MySerializableObject\n+ 2 NavDeepLinkDslBuilder.kt\nandroidx/navigation/NavDeepLinkDslBuilderKt\n*L\n1#1,26:1\n51#2,5:27\n*S KotlinDebug\n*F\n+ 1 Reproduction.kt\nse/fzy/kotlinx_serialization_plugin_bug/MySerializableObject\n*L\n24#1:27,5\n*E\n"})
public final class MySerializableObject {
@NotNull
public static final MySerializableObject INSTANCE = new MySerializableObject();
@NotNull
private static final NavDeepLink deepLink;
// $FF: synthetic field
private static final Lazy $cachedSerializer$delegate;
public static final int $stable;
private MySerializableObject() {
}
@NotNull
public final NavDeepLink getDeepLink() {
return deepLink;
}
/** @deprecated */
// $FF: synthetic method
@Transient
public static void getDeepLink$annotations() {
}
@NotNull
public String toString() {
return "MySerializableObject";
}
public int hashCode() {
return 485428276;
}
public boolean equals(@Nullable Object other) {
if (this == other) {
return true;
} else if (!(other instanceof MySerializableObject)) {
return false;
} else {
MySerializableObject var2 = (MySerializableObject)other;
return true;
}
}
@NotNull
public final KSerializer serializer() {
return this.get$cachedSerializer();
}
// $FF: synthetic method
private final KSerializer get$cachedSerializer() {
return (KSerializer)$cachedSerializer$delegate.getValue();
}
static {
String basePath$iv = "Hello World";
Map typeMap$iv = MapsKt.emptyMap();
Function1 deepLinkBuilder$iv = (Function1)MySerializableObject$special$$inlined$navDeepLink$default$1.INSTANCE;
int $i$f$navDeepLink = false;
deepLink = NavDeepLinkDslBuilderKt.navDeepLink(basePath$iv, Reflection.getOrCreateKotlinClass(MySerializableObject.class), typeMap$iv, deepLinkBuilder$iv);
$cachedSerializer$delegate = LazyKt.lazy(LazyThreadSafetyMode.PUBLICATION, () -> {
return (KSerializer)(new ObjectSerializer("se.fzy.kotlinx_serialization_plugin_bug.MySerializableObject", INSTANCE, new Annotation[0]));
});
$stable = 8;
}
}
// MySerializableObject$special$$inlined$navDeepLink$default$1.java
package se.fzy.kotlinx_serialization_plugin_bug;
import androidx.navigation.NavDeepLinkDslBuilder;
import kotlin.Metadata;
import kotlin.Unit;
import kotlin.jvm.functions.Function1;
import kotlin.jvm.internal.Intrinsics;
import kotlin.jvm.internal.Lambda;
@Metadata(
mv = {2, 0, 0},
k = 3,
xi = 48,
d1 = {"\u0000\u0014\n\u0000\n\u0002\u0010\u0002\n\u0000\n\u0002\u0010\u0000\n\u0002\u0018\u0002\n\u0002\b\u0002\u0010\u0000\u001a\u00020\u0001\"\n\b\u0000\u0010\u0002\u0018\u0001*\u00020\u0003*\u00020\u0004H\n¢\u0006\u0002\b\u0005¨\u0006\u0006"},
d2 = {"<anonymous>", "", "T", "", "Landroidx/navigation/NavDeepLinkDslBuilder;", "invoke", "androidx/navigation/NavDeepLinkDslBuilderKt$navDeepLink$1"}
)
public final class MySerializableObject$special$$inlined$navDeepLink$default$1 extends Lambda implements Function1 {
public static final MySerializableObject$special$$inlined$navDeepLink$default$1 INSTANCE = new MySerializableObject$special$$inlined$navDeepLink$default$1();
public MySerializableObject$special$$inlined$navDeepLink$default$1() {
super(1);
}
public final void invoke(NavDeepLinkDslBuilder $this$null) {
Intrinsics.checkNotNullParameter($this$null, "$this$null");
}
// $FF: synthetic method
// $FF: bridge method
public Object invoke(Object p1) {
this.invoke((NavDeepLinkDslBuilder)p1);
return Unit.INSTANCE;
}
}
Expected behavior
The program should not crash when referencing MySerializableObject
or its serializer.
Written another way: the Reproduction.kt
unit test should pass.
Environment
- Kotlin version: 1.9.22, 1.9.24, 2.0.20
- Library version: 1.6.2, 1.7.3
- Kotlin platforms: JVM
- Gradle version: 8.9
- IDE version (if bug is related to the IDE) Android Studio 2024.2.1 Patch 2