Static final field is null when it shouldn't

Viewed 632

We have some code in our app that is using Java and other that is using Kotlin. We have come across a very strange situation.

The problem shows up on some devices, where it reports platform as being null when passing it to the AutoValue_Session constructor despite us checking whether lastPlatform is not null and providing the constant Platform.MISSING otherwise:

Caused by java.lang.NullPointerException: Null lastPlatform
x.x.x.x.AutoValue_Session.(SourceFile:27)
x.x.x.x.Session.from(SourceFile:28) // from that calls the child constructor
x.x.x.x.Session.(SourceFile:22) // whereNONE_FOUND is defined
x.x.x.x.Session.from(SourceFile:32) // entry point
[...]

Anybody has had this issue with Android and Kotlin interop?

Update: This happens in the wild and with a tiny amount of users. Not being able to replicate it locally yet.

Update 2: The second call to Session.from is caused by the <clinit> of Session which is being loaded into memory for the first time.

Here is the code for the two classes mentioned:

Platform.kt

sealed class Platform {

    abstract val name : String

    sealed class Local : Platform() {

        object Default : Local() {
            override val name: String = "android"
        }

        object Amazon : Local() {
            override val name: String = "android-amazon"
        }
    }

    object Missing : Platform() {
        override val name: String = "missing"
    }

    data class Remote(override val name: String) : Platform()

    companion object {
        @JvmName("from")
        @JvmStatic
        operator fun invoke(name: String?): Platform = when (name) {
            Local.Default.name -> Local.Default
            Local.Amazon.name -> Local.Amazon
            Missing.name -> Missing
            null -> Missing
            else -> Remote(name)
        }

        @JvmField
        val LOCAL : Platform = if (BuildConfig.amazon) Local.Amazon else Local.Generic

        @JvmField
        val MISSING : Platform = Missing
    }
}

Session.java

@AutoValue
public abstract class Session implements Serializable {

    public static final Session NONE_FOUND = from(0, new DateTime(0), Platform.MISSING);

    public static Session from(String id, @Nullable Platform lastPlatform) {
        Platform platform = lastPlatform == null ? Platform.MISSING : lastPlatform;
        return new AutoValue_Session(id, platform);
    }

    public static Session from(RemoteSession remote) {
        return from(
                remote.id(),
                remote.lastPlatform()
        );
    }

    public abstract String id();

    public abstract Platform lastPlatform();

}
0 Answers
Related