Kotlin throw NPE when using Lazy Delegate with Gson

The problem lies in the way Gson instantiates classes while deserializing JSON. Gson uses Java's Unsafe in the UnsafeAllocator:

Class<?> unsafeClass = Class.forName("sun.misc.Unsafe");
Field f = unsafeClass.getDeclaredField("theUnsafe");
f.setAccessible(true);
final Object unsafe = f.get(null);
final Method allocateInstance = unsafeClass.getMethod("allocateInstance", Class.class);

return new UnsafeAllocator() {
    @Override
    @SuppressWarnings("unchecked")
    public <T> T newInstance(Class<T> c) throws Exception {
        assertInstantiable(c);
        return (T) allocateInstance.invoke(unsafe, c); // instantiation of the class
    }
}

What the call allocateInstance.invoke(unsafe, c) does is simply allocate the memory for the class without invoking its constructor. When the class is instantiated, Gson uses reflection to set its fields.

Now back to Kotlin and the lazy delegate. The lazy { } builder actually creates a Lazy<T> object. The method is invoked during the class initialization, i.e. after its constructor has been called.

So, if the constructor isn't invoked during the unsafe allocation, the Lazy<T> delegate won't be created and will hold a null value. Every access to the delegated property calls getValue() on the delegate and in this case results in a NullPointerException.

To solve it you can either use the methods you've already defined (toBar() and toVar()) or create computed properties asBar and asVar instead of lazy ones:

val asBar
    get() = Bar.fromJson(data)

val asVar
    get() = Var.fromJson(data)

However, maybe the better solution would be to leave the Foo class as a dumb wrapper for the data and move the converting logic outside.