NPE with delegate


#1

I have a data-class with an enum property. I also wrote a delegate which gives me that property as a string.

data class POJO (val id: Int, val status: Status) {
    val statusStr by enumValue { status }

    enum class Status {
        TODO, DONE, STARTED
    }
}

fun <T : Enum<T>> enumValue(propFn: () -> T): ReadOnlyProperty<Any, String> =
    object : ReadOnlyProperty<Any, String> {
        override fun getValue(thisRef: Any, property: KProperty<*>)
            = propFn().name
    }

First this works as intended, but when I deserialize the class from JSON I get an NPE when accessing the property:

  java.lang.NullPointerException: Attempt to invoke interface method 'java.lang.Object kotlin.properties.ReadOnlyProperty.getValue(java.lang.Object, kotlin.reflect.KProperty)' on a null object reference 

I figured it was because I’m actually the constructor value in the lambda. I have also tried:

data class POJO (val id: Int, val status: Status) {
    val statusStr by enumValue { this@Reklamation.status }
}

fun <T : Enum<T>> enumValue(propFn: Any.() -> T): ReadOnlyProperty<Any, String> =
    object : ReadOnlyProperty<Any, String> {
        override fun getValue(thisRef: Any, property: KProperty<*>)
            = thisRef.propFn().name
    }

I know there are other ways to solve this, but I don’t understand why it doesn’t work.


#2

The exception happens because the delegate field storing the instance of the object implementing ReadOnlyProperty is null. How exactly do you deserialize your POJO?


#3

With Gson. But I think I know where the problem comes from. Gson uses Unsafe if it doesn’t find a default-constructor: https://github.com/google/gson/blob/master/gson/src/main/java/com/google/gson/internal/UnsafeAllocator.java


#4

Yes, if Gson creates an object in that way, the delegate for the property will not be initialized. You can try Jackson with jackson-kotlin-module instead.


#5

If i have more problems with GSON I’ll switch, but for now I’m just adding a default-constructor.

For the record: there’s an issue about this in GSON: https://github.com/google/gson/issues/445