@PreUpdate method on a Embeddable null on the parent caused NullPointerException

Description

I have a class A with a relation to a BEmbeddable. The BEmbeddable have a @PreUpdate method.

When creating the entity A with BEmbeddable null, then save A, it tries to call the @PreUpdate on B which is null.

Basically the problem is that we try to call the method PreUpdate on a null element of B.

Stack trace of nullpointer in Debug:

1 2 3 4 5 6 7 8 9 10 11 12 invoke:62, NativeMethodAccessorImpl {sun.reflect} invoke:43, DelegatingMethodAccessorImpl {sun.reflect} invoke:498, Method {java.lang.reflect} performCallback:35, EmbeddableCallback {org.hibernate.jpa.event.internal} callback:97, CallbackRegistryImpl {org.hibernate.jpa.event.internal} preCreate:57, CallbackRegistryImpl {org.hibernate.jpa.event.internal} saveWithGeneratedId:116, AbstractSaveEventListener {org.hibernate.event.internal} entityIsTransient:192, DefaultPersistEventListener {org.hibernate.event.internal} onPersist:135, DefaultPersistEventListener {org.hibernate.event.internal} onPersist:62, DefaultPersistEventListener {org.hibernate.event.internal} firePersist:800, SessionImpl {org.hibernate.internal} persist:785, SessionImpl {org.hibernate.internal}

Line 62 is `invoke0(method, obj, args)` with method = @PreUpdate method and obj is null.

Maybe a null check is missing in `performCallback:35, EmbeddableCallback org.hibernate.jpa.event.internal`

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Override public boolean performCallback(Object entity) { try { Object embeddable = embeddableGetter.get( entity ); // <--- embeddable is null callbackMethod.invoke( embeddable ); //<-- missing at least null check here? return true; } catch (InvocationTargetException e) { //keep runtime exceptions as is if ( e.getTargetException() instanceof RuntimeException ) { throw (RuntimeException) e.getTargetException(); } else { throw new RuntimeException( e.getTargetException() ); } } catch (Exception e) { throw new RuntimeException( e ); } }

Printed stack trace:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 java.lang.RuntimeException: java.lang.NullPointerException at org.hibernate.jpa.event.internal.EmbeddableCallback.performCallback(EmbeddableCallback.java:48) at org.hibernate.jpa.event.internal.CallbackRegistryImpl.callback(CallbackRegistryImpl.java:97) at org.hibernate.jpa.event.internal.CallbackRegistryImpl.preCreate(CallbackRegistryImpl.java:57) at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:116) at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:192) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:135) at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:62) at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:800) at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:785) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:301) at com.sun.proxy.$Proxy113.persist(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:508) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:515) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.doInvoke(RepositoryFactorySupport.java:500) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:477) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.projection.DefaultMethodInvokingMethodInterceptor.invoke(DefaultMethodInvokingMethodInterceptor.java:56) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.java:99) at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:282) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:136) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:133) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:57) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) at com.sun.proxy.$Proxy152.save(Unknown Source)

Environment

Developpement

Status

Assignee

Vlad Mihalcea

Reporter

David Prévost

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

5.3.6

Priority

Major