I’m migrating my UserType class from Hibernate 5 to 6. As far as I understand the rules, I should use CompositeUserType because my mapped class is rather complex and encapsulates several properties to be persisted. This can’t be accomplished by UserType according to Hibernate 6’s JavaDoc. For the most part, it works. But there is one particular scenario where it can’t handle the cascading merge; I got a NullPointerException, as follows:
java.lang.NullPointerException: Cannot invoke “org.hibernate.property.access.spi.Setter.set(Object, Object)” because the return value of “org.hibernate.property.access.spi.PropertyAccess.getSetter()” is null
See entire exception stack trace I created a minimal sample project to reproduce the problem. @beikov identified it as a bug. For your convenience, I excerpt the important code from my sample project for a quick read. Here is my VaultValue type encapsulating a piece of data securely stored in a Vault:
Here is my CompositeUserType class that maps the VaultValue type:
In my model, I have two entity classes:
- Encounter - an encounter in a healthcare setting
- Observation - a physician’s observation of the patient
An Encounter has a collection of Observations; basically, Encounter and Observation have a cascade one-to-many relation. Both the Encounter entity and the Observation entity have a property of my VaultValue class. By and large, they seem to work with Hibernate 6.1.6 (via Spring Boot 3.0.1). However, when an Encounter instance is re-saved after some new Observation instances are added to it, I get NullPointerException caused by PropertyAccessCompositeUserTypeImpl::getSetter() which always returns null. Here is the Observation entity class:
Here is the Encounter entity class:
The following is the test code that reproduces the NullPointerException (i.e. the Test Case 2 in HibernateApplicationTests code in my minimal sample project, see the link above):
Note:
- encounterRepository is an injected Spring JPA Repository
- mockPersistToVault() just assigns vaultId an arbitrary number for the VaultValue argument
I could work around it by saving every Observation in the collection first before re-saving the Encounter. However, this shouldn’t be necessary because I set up cascade for the one-to-many relation. In fact, I didn’t need to do so with Hibernate 5.6.14. |