Search code examples
androidkotlingsonlocaldate

why wont my LocalDate.parse work with a value inserted from gson?


I have a class:

data class Day(val date: String, val events: List<Event>){
    val localDateTimeDate: LocalDate by lazy {
        LocalDate.parse(date)
    }
}

This gets filled from a JSON string (eg. {"date": "2019-06-26", "events": []}.

If I read someDay.date, I get "2019-06-26", so the filling part works. If I read someDay.localDateTimeDate, I get a nullpointer exception, and I don't see why.

Now, if I go in REPL and fill a "Day" by hand (ie. val day = Day("2019-06-26"", emptyList()) this works. If I make my android phone do LocalDate.parse("2019-06-26"), that works.

Day gets filled by:

    fun receiveDays(): List<Day> {
        val listType = object : TypeToken<List<Day>>() { }.type
        val jsonData = (client.readFromSocket()!!.message).toString(Charsets.UTF_8)
        val daysList =(Gson().fromJson<List<Day>>(jsonData, listType))
        client.sendOK()
        return daysList

If I try to read someDay.localDateTimeDate, I get a nullpointer exception:

2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err: java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object kotlin.Lazy.getValue()' on a null object reference
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at nl.joozd.joozdter.data.Day.getLocalDateTimeDate(Unknown Source:25)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at nl.joozd.joozdter.ui.PdfParserActivity$onCreate$$inlined$let$lambda$1.invoke(PdfParserActivity.kt:140)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at nl.joozd.joozdter.ui.PdfParserActivity$onCreate$$inlined$let$lambda$1.invoke(PdfParserActivity.kt:28)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Async.kt:143)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at org.jetbrains.anko.AsyncKt$doAsync$1.invoke(Unknown Source:0)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at org.jetbrains.anko.AsyncKt$sam$java_util_concurrent_Callable$0.call(Unknown Source:2)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:301)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2019-08-13 00:06:13.075 21870-21942/nl.joozd.joozdter W/System.err:     at java.lang.Thread.run(Thread.java:764)

Solution

  • If a class doesn't have parameterless constructor, Gson creates an object without calling the constructor, thus the field that stores lazy delegate doesn't get initialized and you get a NullPointerException when accessing the property delegated to it.

    See also this question for the possible solutions: Why Kotlin data classes can have nulls in non-nullable fields with Gson?