Problem with lazy loading and lack of a backing field


Working with Entities in JPA I come across something like this:

class Foo {
	@OneToMany(mappedBy = "foo")
	val bars : MutableList<Bar> by lazy { ArrayList<Bar>() }

This is a nice pattern such that when the Entity is new, it’ll create a new empty List for Bars, but the underlying framework will set the list (with field access) for existing Foos.

the problem is that kotlin generates the error:

Kotlin: This annotation is not applicable to target ‘member property without backing field’

Not a big deal, but was wondering if there is a nice way to make this work.


Move your annotation to the getter:

    val bars : MutableList<Bar>
        @OneToMany(mappedBy = "foo")
        get() {
            return ArrayList<Bar>() 

Note that the code above is not strictly equivalent to your original lazy code, though.


Thanks for the response. Yea, I investigated your solution but the problem is that as soon as I implement the lazy loading in the get method the compiler is no longer willing to guarantee the getter will never be null, so the property type has to be changed to allow nulls, which I would like to avoid. I just settled on initializing the property directly with an empty array list, and accept the very minor overhead of an unnecessary empty array list creation in some circumstances. It would have been kinda lucky for this to work anyway since the JPA provider is fiddling with the fields underneath the hood, and the lazy delegate wasn’t really designed for this.

        @get:OneToMany(mappedBy = "foo")
	val bars : MutableList<Bar> by lazy { ArrayList<Bar>() }