[JIRA] (HHH-16937) Persisting entity with nullable @Any field throws “not-null property references a null or transient value”
by Jake Laack (JIRA)
Jake Laack ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=5de53c9... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiYTVhOGJkOTZl... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16937?atlOrigin=eyJpIjoiYTVhOG... ) HHH-16937 ( https://hibernate.atlassian.net/browse/HHH-16937?atlOrigin=eyJpIjoiYTVhOG... ) Persisting entity with nullable @Any field throws “not-null property references a null or transient value” ( https://hibernate.atlassian.net/browse/HHH-16937?atlOrigin=eyJpIjoiYTVhOG... )
Issue Type: Bug Affects Versions: 6.2.6 Assignee: Unassigned Components: regression Created: 14/Jul/2023 09:05 AM Environment: JVM 17 Priority: Major Reporter: Jake Laack ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=5de53c9... )
Since the solution to @Any and @ManyToAny Associations Fail in Spring Boot 3 ( https://discourse.hibernate.org/t/any-and-manytoany-associations-fail-in-... ) is available , I decided to update the repository I used to demonstrate that problem ( https://github.com/dirkniblick/polymorphWithoutSpringboot/tree/develop ). I’ve updated Hibernate from 6.1.7.Final to 6.2.6.Final (and the other packages), ran the HibernatePolymorphApplicationTests and the null pointer exception from the other post was gone!
Unfortunately, it was replaced with another one:
not-null property references a null or transient value : com.example.hibernatepolymorph.entity.PropertyHolder.property
org.hibernate.PropertyValueException: not-null property references a null or transient value : com.example.hibernatepolymorph.entity.PropertyHolder.property
at app//org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:109)
at app//org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:54)
at app//org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:124)
at app//org.hibernate.action.internal.AbstractEntityInsertAction.makeEntityManaged(AbstractEntityInsertAction.java:133)
at app//org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:299)
at app//org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:272)
at app//org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:259)
at app//org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:376)
at app//org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:277)
at app//org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at app//org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:136)
at app//org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:175)
at app//org.hibernate.event.internal.DefaultPersistEventListener.persist(DefaultPersistEventListener.java:93)
at app//org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:77)
at app//org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:54)
at app//org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:127)
at app//org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:755)
at app//org.hibernate.internal.SessionImpl.persist(SessionImpl.java:739)
at app//com.example.hibernatepolymorph.HibernatePolymorphApplicationTests.save(HibernatePolymorphApplicationTests.java:122)
at app//com.example.hibernatepolymorph.HibernatePolymorphApplicationTests.createPropertyHolder(HibernatePolymorphApplicationTests.java:60)
at java.base(a)17.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.2/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base@17.0.2/java.lang.reflect.Method.invoke(Method.java:568)
at app//org.junit.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:727)
at app//org.junit.jupiter.engine.execution.MethodInvocation.proceed(MethodInvocation.java:60)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$ValidatingInvocation.proceed(InvocationInterceptorChain.java:131)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.intercept(TimeoutExtension.java:156)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestableMethod(TimeoutExtension.java:147)
at app//org.junit.jupiter.engine.extension.TimeoutExtension.interceptTestMethod(TimeoutExtension.java:86)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker$ReflectiveInterceptorCall.lambda$ofVoidMethod$0(InterceptingExecutableInvoker.java:103)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.lambda$invoke$0(InterceptingExecutableInvoker.java:93)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain$InterceptedInvocation.proceed(InvocationInterceptorChain.java:106)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.proceed(InvocationInterceptorChain.java:64)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.chainAndInvoke(InvocationInterceptorChain.java:45)
at app//org.junit.jupiter.engine.execution.InvocationInterceptorChain.invoke(InvocationInterceptorChain.java:37)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:92)
at app//org.junit.jupiter.engine.execution.InterceptingExecutableInvoker.invoke(InterceptingExecutableInvoker.java:86)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$7(TestMethodTestDescriptor.java:217)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:213)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:138)
at app//org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:68)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:151)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base@17.0.2/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at java.base@17.0.2/java.util.ArrayList.forEach(ArrayList.java:1511)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:41)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$6(NodeTestTask.java:155)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$8(NodeTestTask.java:141)
at app//org.junit.platform.engine.support.hierarchical.Node.around(Node.java:137)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$9(NodeTestTask.java:139)
at app//org.junit.platform.engine.support.hierarchical.ThrowableCollector.execute(ThrowableCollector.java:73)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:138)
at app//org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:95)
at app//org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:35)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:57)
at app//org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:54)
at app//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:107)
at app//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:88)
at app//org.junit.platform.launcher.core.EngineExecutionOrchestrator.lambda$execute$0(EngineExecutionOrchestrator.java:54)
at app//org.junit.platform.launcher.core.EngineExecutionOrchestrator.withInterceptedStreams(EngineExecutionOrchestrator.java:67)
at app//org.junit.platform.launcher.core.EngineExecutionOrchestrator.execute(EngineExecutionOrchestrator.java:52)
at app//org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:114)
at app//org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:86)
at app//org.junit.platform.launcher.core.DefaultLauncherSession$DelegatingLauncher.execute(DefaultLauncherSession.java:86)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.processAllTestClasses(JUnitPlatformTestClassProcessor.java:110)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor$CollectAllTestClassesExecutor.access$000(JUnitPlatformTestClassProcessor.java:90)
at org.gradle.api.internal.tasks.testing.junitplatform.JUnitPlatformTestClassProcessor.stop(JUnitPlatformTestClassProcessor.java:85)
at org.gradle.api.internal.tasks.testing.SuiteTestClassProcessor.stop(SuiteTestClassProcessor.java:62)
at java.base(a)17.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base@17.0.2/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
at java.base@17.0.2/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base@17.0.2/java.lang.reflect.Method.invoke(Method.java:568)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:36)
at org.gradle.internal.dispatch.ReflectionDispatch.dispatch(ReflectionDispatch.java:24)
at org.gradle.internal.dispatch.ContextClassLoaderDispatch.dispatch(ContextClassLoaderDispatch.java:33)
at org.gradle.internal.dispatch.ProxyDispatchAdapter$DispatchingInvocationHandler.invoke(ProxyDispatchAdapter.java:94)
at jdk.proxy1/jdk.proxy1.$Proxy2.stop(Unknown Source)
at org.gradle.api.internal.tasks.testing.worker.TestWorker$3.run(TestWorker.java:193)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.executeAndMaintainThreadName(TestWorker.java:129)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:100)
at org.gradle.api.internal.tasks.testing.worker.TestWorker.execute(TestWorker.java:60)
at org.gradle.process.internal.worker.child.ActionExecutionWorker.execute(ActionExecutionWorker.java:56)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:113)
at org.gradle.process.internal.worker.child.SystemApplicationClassLoaderWorker.call(SystemApplicationClassLoaderWorker.java:65)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.run(GradleWorkerMain.java:69)
at app//worker.org.gradle.process.internal.worker.GradleWorkerMain.main(GradleWorkerMain.java:74)
It dies at the save method here:
PropertyHolder namePropertyHolder = new PropertyHolder();
namePropertyHolder.setId(1L);
save(namePropertyHolder);
System.out.printf("Created: %s%n", namePropertyHolder);
...
void save(Object object) {
EntityTransaction transaction = entityManager.getTransaction();
transaction.begin();
entityManager.persist(object);
transaction.commit();
}
If you look at the definition for PropertyHolder.property, you’ll see null values should be allowed:
@Any
@AnyDiscriminator(DiscriminatorType.STRING)
@AnyDiscriminatorValue(discriminator = "S", entity = StringProperty.class)
@AnyDiscriminatorValue(discriminator = "I", entity = IntegerProperty.class)
@AnyKeyJavaClass(Long.class)
@Column(name = "property_type")
@JoinColumn(name = "property_id")
private Property<?> property;
The exception persists even if I apply the defaults here:
@Any(optional = true)
@AnyDiscriminator(DiscriminatorType.STRING)
@AnyDiscriminatorValue(discriminator = "S", entity = StringProperty.class)
@AnyDiscriminatorValue(discriminator = "I", entity = IntegerProperty.class)
@AnyKeyJavaClass(Long.class)
@Column(name = "property_type", nullable = true)
@JoinColumn(name = "property_id", nullable = true)
private Property<?> property;
If I change the test to populate the property field prior to persisting, the test succeeds:
PropertyHolder namePropertyHolder = new PropertyHolder();
namePropertyHolder.setId(1L);
namePropertyHolder.setProperty(nameProperty);
save(namePropertyHolder);
System.out.printf("Created: %s%n", namePropertyHolder);
I feel like the not-null property references a null or transient value exception above is incorrect here.
FYI, here’s the 5.6.15.Final version of the same repository ( https://github.com/dirkniblick/polymorphWithoutSpringBootHibernate5.6.15F... ) which performs the same test successfully.
( https://hibernate.atlassian.net/browse/HHH-16937#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16937#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100232- sha1:33a7c72 )
2 years, 9 months
[JIRA] (HHH-16936) Entity not being removed from persistence context after a delete in JPQL
by Jean-Baptiste Hainaut (JIRA)
Jean-Baptiste Hainaut ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=712020%... ) *created* an issue
Hibernate ORM ( https://hibernate.atlassian.net/browse/HHH?atlOrigin=eyJpIjoiNDNmNDYwMzkz... ) / Bug ( https://hibernate.atlassian.net/browse/HHH-16936?atlOrigin=eyJpIjoiNDNmND... ) HHH-16936 ( https://hibernate.atlassian.net/browse/HHH-16936?atlOrigin=eyJpIjoiNDNmND... ) Entity not being removed from persistence context after a delete in JPQL ( https://hibernate.atlassian.net/browse/HHH-16936?atlOrigin=eyJpIjoiNDNmND... )
Issue Type: Bug Affects Versions: 6.2.5 Assignee: Unassigned Components: hibernate-core Created: 14/Jul/2023 07:37 AM Environment: Spring boot 3.1.1 with Hibernate-core 6.2.5 Priority: Minor Reporter: Jean-Baptiste Hainaut ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=712020%... )
When using a composite id, the entity is not removed from the persistance context with a delete query written in JPQL
Our Entity and composite id :
@Entity
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true )
public class SchoolSetting {
@EmbeddedId
private final SchoolSettingId id;
@Getter
private boolean activated;
public SchoolSetting(@NonNull final String schoolId,
@NonNull final String key,
final boolean activated) {
this.id = new SchoolSettingId(schoolId, key);
this.activated = activated;
}
public String getKey() {
return this.id.getKey();
}
}
@Embeddable
@NoArgsConstructor(access = AccessLevel.PRIVATE, force = true )
@Getter(AccessLevel.PROTECTED)
@EqualsAndHashCode
public class SchoolSettingId implements Serializable {
private final String schoolId;
private final String key;
public SchoolSettingId(@NonNull final String schoolId,
@NonNull final String key) {
this.schoolId = schoolId;
this.key = key;
}
}
The repository :
interface SpringDataSchoolSettingRepository extends CrudRepository<SchoolSetting, SchoolSettingId> {
@Query( "delete from SchoolSetting s WHERE s.id.key = :id" )
@Modifying
void deleteById(@Param( "id" ) SchoolSettingId id);
}
The following test fail without the testEntityManager.clear() as the entity is still in the persistence context. We we are able to reproduce the same behavior with production code inside the same transaction
@DataJpaTest
@AutoConfigureTestDatabase(replace = AutoConfigureTestDatabase.Replace.NONE)
@Import(JpaSchoolSettingRepository.class)
class JpaSchoolSettingRepositoryIT {
static String SCHOOL_ID = "MY_SCHOOL" ;
@Autowired
TestEntityManager testEntityManager;
@Autowired
JpaSchoolSettingRepository jpaSchoolSettingRepository;
@Test
void deleteTwiceShouldntThrowAnyException() {
testEntityManager.persistAndFlush(createSetting());
assertThat(jpaSchoolSettingRepository.get( new SchoolSettingId(SCHOOL_ID, "ABSENCE_FOR_DAY_OFF" )))
.isNotEmpty();
jpaSchoolSettingRepository.delete( new SchoolSettingId(SCHOOL_ID, "ABSENCE_FOR_DAY_OFF" ));
//testEntityManager.clear();
assertThat(jpaSchoolSettingRepository.get( new SchoolSettingId(SCHOOL_ID, "ABSENCE_FOR_DAY_OFF" )))
.isEmpty();
assertThatCode(() -> jpaSchoolSettingRepository.delete( new SchoolSettingId(SCHOOL_ID, "ABSENCE_FOR_DAY_OFF" )))
.doesNotThrowAnyException();
}
private SchoolSetting createSetting() {
return new SchoolSetting(SCHOOL_ID, ABSENCE_FOR_DAY_OFF, true );
}
}
If we change the query to the following, it work as expected :
@Query( "delete from SchoolSetting s WHERE s.id.key = :schoolId and s.id.schoolId = :key" )
@Modifying
void deleteById( String schoolId, String key);
So we conclude that the bug is related with the handling of the composite key
( https://hibernate.atlassian.net/browse/HHH-16936#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16936#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100232- sha1:33a7c72 )
2 years, 9 months