You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

生产环境Android应用LocalDateTime调用isAfter()引发空指针异常求助

NullPointerException when calling LocalDateTime.isAfter() after Paper deserialization (ThreeTen BP)

I’ve run into a similar issue with ThreeTen BP’s date/time classes and Android serialization libraries like Paper, so let me break down what’s likely happening and how to fix it.

The Root Cause

Your null checks are passing because the LocalDateTime instance itself isn’t null—but its internal LocalDate field is null after deserialization. Paper’s default reflection-based serialization doesn’t properly handle complex immutable value types like ThreeTen’s LocalDateTime. When you deserialize the TemplatesCacheInfo object, Paper might create a "broken" LocalDateTime instance where critical internal fields (like year in LocalDate) aren’t initialized, even though the object reference isn’t null.

This explains why your null checks (templatesCacheInfo.lastUpdate != null) pass, but calling isAfter() triggers an NPE when accessing the internal year field.

Fix Recommendations

1. Implement a Custom Serializer for LocalDateTime

The most robust fix is to tell Paper how to properly serialize/deserialize LocalDateTime with a custom adapter. Here’s a working example:

import org.threeten.bp.LocalDateTime
import org.threeten.bp.format.DateTimeFormatter
import io.paperdb.Serializer

class LocalDateTimeSerializer : Serializer<LocalDateTime> {
    private val formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME

    override fun write(obj: LocalDateTime): ByteArray {
        // Serialize as a standard ISO 8601 string
        return formatter.format(obj).toByteArray(Charsets.UTF_8)
    }

    override fun read(bytes: ByteArray): LocalDateTime {
        // Deserialize from the stored string
        val dateString = String(bytes, Charsets.UTF_8)
        return LocalDateTime.parse(dateString, formatter)
    }

    override fun getUniqueTag(): String {
        return "org.threeten.bp.LocalDateTime"
    }
}

Register this serializer when initializing Paper in your app:

Paper.init(context)
Paper.register(LocalDateTime::class.java, LocalDateTimeSerializer())

This ensures LocalDateTime is stored as a safe, human-readable string instead of relying on Paper’s default serialization which can break internal object structure.

2. Store LocalDateTime as a String/Timestamp Instead

If you don’t want to deal with custom serializers, modify your TemplatesCacheInfo to store the date as a string (or epoch timestamp) instead of the raw LocalDateTime:

data class TemplatesCacheInfo(
    val lastUpdate: String, // Store ISO 8601 formatted string
    val templatesLanguage: String,
    val appVersion: String?
) : Serializable

// When saving to Paper:
val cacheInfo = TemplatesCacheInfo(
    lastUpdate = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
    templatesLanguage = "en",
    appVersion = "1.0.0"
)

// When reading and using the date:
val lastUpdateDate = LocalDateTime.parse(cacheInfo.lastUpdate, DateTimeFormatter.ISO_LOCAL_DATE_TIME)

This bypasses the serialization issue entirely by using a primitive type that Paper handles reliably.

3. Add Defensive Checks (Temporary Workaround)

As a quick fix while implementing the proper solution, wrap the isAfter() call in a try-catch and add an extra check to validate the LocalDateTime instance:

private fun isLastUpdateChanged(
    templatesCacheInfo: TemplatesCacheInfo?, lastUpdateDate: LocalDateTime?
): Boolean {
    return try {
        if (lastUpdateDate != null && templatesCacheInfo != null) {
            // Trigger early NPE if internal fields are broken
            templatesCacheInfo.lastUpdate.run {
                year // Access internal field to validate instance
                isAfter(lastUpdateDate)
            }
        } else false
    } catch (e: NullPointerException) {
        false // Treat broken instances as "not changed"
    }
}

This will catch broken instances and prevent crashes, but it’s not a long-term solution.

4. Update Paper to the Latest Version

Occasionally, serialization bugs get fixed in newer Paper releases. Check if you’re using the latest stable version and upgrade if possible—it might resolve the issue out of the box.

Final Note

The custom serializer approach is the most maintainable long-term solution, as it ensures ThreeTen’s date/time classes are handled correctly across all serialization operations.

内容的提问来源于stack exchange,提问作者Jakub Anioła

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 18:07:40