How to disable JPA 2 callback methods and object listeners

I have some classes (entities) with methods annotated with @PostLoad , @PrePersist etc., And the classes have @EntityListeners annotation. I want to disable the processing of callback methods and listeners in my test environment.

Removing part of the code is not possible because the tests are executed on the CI server, and I have no way to change the code for tests only.

Is it possible to disable callback methods and entity listeners in JPA 2 configuration? I am using hibernate.

+7
source share
3 answers

I am sure this is not possible. The mechanism of annotated entities is very static, so I did not use it.

What I did in such situations was to define the interfaces for the objects to be implemented, for example:

 interface UpdateValidation{ void preUpdate(); } interface PersistValidation{ void prePersist(); } // etc. 

Now define one EntityListener that validates entities for the above interfaces. In the @PreUpdate method check UpdateValidation , in the @PrePersist method check PersistValidation . Then pass the entity methods.

This way you have one Listener that controls all the functionality, and you can enable or disable this listener with XML configuration.


Update full implementation:

 public class DelegatingEntityListener{ public interface PrePersistSupport{ void prePersist(); } public interface PostPersistSupport{ void postPersist(); } public interface PreRemoveSupport{ void preRemove(); } public interface PostRemoveSupport{ void postRemove(); } public interface PreUpdateSupport{ void preUpdate(); } public interface PostUpdateSupport{ void postUpdate(); } public interface PostLoadSupport{ void postLoad(); } @PrePersist public void prePersist(final Object entity){ if(entity instanceof PrePersistSupport){ ((PrePersistSupport) entity).prePersist(); } } @PostPersist public void postPersist(final Object entity){ if(entity instanceof PostPersistSupport){ ((PostPersistSupport) entity).postPersist(); } } @PreRemove public void preRemove(final Object entity){ if(entity instanceof PreRemoveSupport){ ((PreRemoveSupport) entity).preRemove(); } } @PostRemove public void postRemove(final Object entity){ if(entity instanceof PostRemoveSupport){ ((PostRemoveSupport) entity).postRemove(); } } @PreUpdate public void preUpdate(final Object entity){ if(entity instanceof PreUpdateSupport){ ((PreUpdateSupport) entity).preUpdate(); } } @PostUpdate public void postUpdate(final Object entity){ if(entity instanceof PostUpdateSupport){ ((PostUpdateSupport) entity).postUpdate(); } } @PostLoad public void postLoad(final Object entity){ if(entity instanceof PostLoadSupport){ ((PostLoadSupport) entity).postLoad(); } } } 

And in case you wondered: no, I did not write the code manually. Here is the code that wrote this code :-) You can easily customize it to your own needs.

 public static void main(final String[] args){ final StringBuilder ib = new StringBuilder(); // interface builder final StringBuilder sb = new StringBuilder(); // method builder for(final Class<? extends Annotation> annotationType : Arrays .asList( // all lifecycle annotations: PrePersist.class, PostPersist.class, PreRemove.class, PostRemove.class, PreUpdate.class, PostUpdate.class, PostLoad.class)){ final String annotationName = annotationType.getSimpleName(); final String lower = annotationName .substring(0, 1) .toLowerCase() .concat(annotationName.substring(1)); ib.append("public interface ") .append(annotationName) .append("Support{\n\tvoid ") .append(lower) .append("();\n}\n\n"); sb.append('@') .append(annotationName) .append(" public void ") .append(lower) .append("(Object entity){\nif(entity instanceof ") .append(annotationName) .append("Support){((") .append(annotationName) .append("Support)entity).") .append(lower) .append("();}}\n\n"); } System.out.println(ib.toString()); System.out.println(sb.toString()); } 

The disadvantage, of course, is that the JPA provider cannot cache the used life cycle methods, but I would say that this is the only way to get what you need / need.

+1
source

If you want to remove all JPA listeners from Hibernate 4.3.5 (the only one I tested), this can be done. I will not show how to get EntityMangerFactory (emf in the lower code), but after that the lower code should be added / run.


Explanation: It seems that there is a very central class called org.hibernate.jpa.event.internal.jpa.CallbackRegistryImpl that contains all registered listeners and callbacks for objects. Replacing the registry with an empty one will not return callbacks.

 SessionFactoryImpl sessionFactory = (SessionFactoryImpl) ((EntityManagerFactoryImpl) emf).getSessionFactory(); EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class); CallbackRegistryImpl emptyRegistry= new CallbackRegistryImpl(); for ( EventType eventType : EventType.values() ) { final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); for ( Object listener : eventListenerGroup.listeners() ) { if ( CallbackRegistryConsumer.class.isInstance( listener ) ) { ( (CallbackRegistryConsumer) listener ).injectCallbackRegistry( emptyRegistry ); } } } 
+6
source

I recently had the same issue with entities annotated with @EntityListeners using EclipseLink. Here is what I did to remove the listeners:

 private fun disableEntityListeners(entityManager: EntityManager) { entityManager.metamodel.entities .map { it as EntityTypeImpl<*> } .forEach { it.descriptor.eventManager.entityListenerEventListeners.clear() } } 

(This is Kotlin code, but you get the point.)

0
source

Source: https://habr.com/ru/post/1344939/


All Articles