Skip to content

ExceptionInInitializerError when @Serializable data object contains NavDeepLink #2857

Open
@FelixZY

Description

@FelixZY

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\u0001\u0003J\t\u0010\u000b\u001a\u00020\f\u0001J\u000f\u0010\r\u001a\b\u0012\u0004\u0012\u00020\u00000\u000e\u0001J\t\u0010\u000f\u001a\u00020\u0010\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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions