Kotlin Relationships for Spring Data, Nullable, Collection & Individual

Greetings all,
I wonder if any of you can assist me with a concern.

I have been experimenting with Spring Data Neo4j for Kotlin over the past few days.

Spring Boot version 2.2.4.RELEASE
Kotlin version 1.3.61
Neo4j version 4.0.0

As an example, if I set up a class such as:

data class Kennel constructor (@Id @GeneratedValue val id: Long? = null, @Relationship val dog: Dog) {

where a Dog is:

data class Dog constructor (@Id @GeneratedValue var id: Long? = null, @Relationship var name: String) {

and then try to save and load an object of this Kennel class:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class KennelRepositoryTest @Autowired constructor (val kennelRepository: KennelRepository,
                                                   val session: Session) {
    var dogWrite: Dog = Dog(name = "rover");
    var kennelWrite: Kennel = Kennel(dog = dogWrite)

    fun beforeEach() {

    fun findById() {
        val kennelRead: Kennel = kennelRepository.findById(kennelWrite.id!!).orElseGet (null)
        assertEquals(kennelWrite, kennelRead)

I see an IllegalArgumentException on findById of:

java.lang.IllegalArgumentException: Parameter specified as non-null is null: method w.resourceserver.domain.Kennel.<init>, parameter dog

resulting from:

Caused by: org.springframework.data.mapping.model.MappingInstantiationException: Failed to instantiate w.resourceserver.domain.Kennel using constructor fun <init>(kotlin.Long?, w.resourceserver.domain.Dog): w.resourceserver.domain.Kennel with arguments null,null,1,null

If I instead use an alternative Kennel with a Nullable dog

data class KennelWithNullable constructor (@Id @GeneratedValue val id: Long? = null, @Relationship val dog: Dog?) {

or a dog in a collection:

data class KennelWithSet constructor (@Id @GeneratedValue val id: Long? = null, @Relationship val dogSet: Set<Dog>) {

the findById method seems to work fine.

Is this expected behaviour or should I try and continue debugging ?

Many thanks for any feedback.

Unfortunately you are correct and this is expected behaviour we cannot easily fix.
The underlying mapping framework (Neo4j-OGM) has no concept of instantiating the related classes before the main entity. As a result the Kennel will get created (if the Dogs are a collection with an empty one) and the relationship will get filled / set later in the mapping phase.

On another node: If you want to get started with Spring Data Neo4j in general, I suggest to have a look at Spring Data Neo4j RX. It is planned to be the successor of Spring Data Neo4j in the long run. It has already the immutability support you are looking for.

1 Like

Thanks for the clarification. Much appreciated. I will start to look into Spring Data Neo4j RX.

Also, I have noted that if, on the same setup, I make a slight modification to the Dog to include a Kotlin Int:

data class Dog constructor (@Id @GeneratedValue var id: Long? = null, var name: String, var owners:Int) {}

then with the addition in my build.gradle.kts of an:

implementation ("org.springframework.boot:spring-boot-starter-data-rest")

I can realise an error of:

No converter found capable of converting from type [java.lang.Long] to type [int]

even with a Nullable dog or a dog in a collection.

So, are there meant to be inbuilt converters to support Kotlin Int ?
Or am I barking up the wrong tree here, no pun intended.
If not, would it be desirable to have them ?
I should add that Kotlin Longs seem to work fine.