Head's Up! These forums are read-only. All users and content have migrated. Please join us at community.neo4j.com.
02-19-2020 04:02 PM
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:
@NodeEntity
data class Kennel constructor (@Id @GeneratedValue val id: Long? = null, @Relationship val dog: Dog) {
}
where a Dog is:
@NodeEntity
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:
@ExtendWith(SpringExtension::class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@Transactional
class KennelRepositoryTest @Autowired constructor (val kennelRepository: KennelRepository,
val session: Session) {
var dogWrite: Dog = Dog(name = "rover");
var kennelWrite: Kennel = Kennel(dog = dogWrite)
@BeforeEach
fun beforeEach() {
session.purgeDatabase()
kennelRepository.save<Kennel>(kennelWrite)
session.clear()
}
@Test
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
@NodeEntity
data class KennelWithNullable constructor (@Id @GeneratedValue val id: Long? = null, @Relationship val dog: Dog?) {
}
or a dog in a collection:
@NodeEntity
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.
Solved! Go to Solution.
02-19-2020 11:53 PM
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 Dog
s 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.
02-19-2020 11:53 PM
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 Dog
s 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.
02-20-2020 03:15 AM
Thanks for the clarification. Much appreciated. I will start to look into Spring Data Neo4j RX.
02-23-2020 07:20 AM
Also, I have noted that if, on the same setup, I make a slight modification to the Dog to include a Kotlin Int:
@NodeEntity
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.
All the sessions of the conference are now available online