HHH-13198 Introduce a global configuration flag to disable JPA callbacks
This commit is contained in:
parent
29e135c015
commit
a78c56c01f
|
@ -100,6 +100,7 @@ import static org.hibernate.cfg.AvailableSettings.MAX_FETCH_DEPTH;
|
|||
import static org.hibernate.cfg.AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER;
|
||||
import static org.hibernate.cfg.AvailableSettings.NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE;
|
||||
import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS;
|
||||
import static org.hibernate.cfg.AvailableSettings.JPA_CALLBACKS_ENABLED;
|
||||
import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES;
|
||||
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
|
||||
import static org.hibernate.cfg.AvailableSettings.PROCEDURE_NULL_PARAM_PASSING;
|
||||
|
@ -196,6 +197,9 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
private boolean orderInsertsEnabled;
|
||||
private boolean postInsertIdentifierDelayed;
|
||||
|
||||
// JPA callbacks
|
||||
private boolean callbacksEnabled;
|
||||
|
||||
// multi-tenancy
|
||||
private MultiTenancyStrategy multiTenancyStrategy;
|
||||
private CurrentTenantIdentifierResolver currentTenantIdentifierResolver;
|
||||
|
@ -346,6 +350,8 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
DISABLE_DELAYED_IDENTIFIER_POST_INSERTS, configurationSettings, false
|
||||
);
|
||||
|
||||
this.callbacksEnabled = ConfigurationHelper.getBoolean( JPA_CALLBACKS_ENABLED, configurationSettings, true );
|
||||
|
||||
this.jtaTrackByThread = cfgService.getSetting( JTA_TRACK_BY_THREAD, BOOLEAN, true );
|
||||
|
||||
this.querySubstitutions = ConfigurationHelper.toMap( QUERY_SUBSTITUTIONS, " ,=;:\n\t\r\f", configurationSettings );
|
||||
|
@ -1053,6 +1059,11 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions {
|
|||
return postInsertIdentifierDelayed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areJPACallbacksEnabled() {
|
||||
return callbacksEnabled;
|
||||
}
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// In-flight mutation access
|
||||
|
||||
|
|
|
@ -437,4 +437,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public int getQueryStatisticsMaxSize() {
|
||||
return delegate.getQueryStatisticsMaxSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areJPACallbacksEnabled() {
|
||||
return delegate.areJPACallbacksEnabled();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -299,4 +299,9 @@ public interface SessionFactoryOptions {
|
|||
default boolean isPostInsertIdentifierDelayableEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
default boolean areJPACallbacksEnabled() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -923,6 +923,14 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings {
|
|||
*/
|
||||
String ORDER_INSERTS = "hibernate.order_inserts";
|
||||
|
||||
/**
|
||||
* JPA Callbacks are enabled by default. Set this to {@code false} to disable them.
|
||||
* Mostly useful to save a bit of memory when they are not used.
|
||||
* Experimental and will likely be removed as soon as the memory overhead is resolved.
|
||||
* @since 5.4
|
||||
*/
|
||||
String JPA_CALLBACKS_ENABLED = "hibernate.jpa_callbacks.enabled";
|
||||
|
||||
/**
|
||||
* Default precedence of null values in {@code ORDER BY} clause. Supported options: {@code none} (default),
|
||||
* {@code first}, {@code last}.
|
||||
|
|
|
@ -43,12 +43,12 @@ import org.hibernate.event.service.spi.DuplicationStrategy;
|
|||
import org.hibernate.event.service.spi.EventListenerRegistrationException;
|
||||
import org.hibernate.event.service.spi.EventListenerRegistry;
|
||||
import org.hibernate.event.spi.EventType;
|
||||
import org.hibernate.jpa.event.internal.CallbackBuilderLegacyImpl;
|
||||
import org.hibernate.jpa.event.internal.CallbackRegistryImpl;
|
||||
import org.hibernate.jpa.event.internal.CallbackRegistryImplementor;
|
||||
import org.hibernate.jpa.event.internal.CallbacksFactory;
|
||||
import org.hibernate.jpa.event.spi.CallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.service.spi.Stoppable;
|
||||
|
||||
|
@ -96,7 +96,7 @@ public class EventListenerRegistryImpl implements EventListenerRegistry, Stoppab
|
|||
private Map<Class,Object> listenerClassToInstanceMap = new HashMap<>();
|
||||
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
private final CallbackRegistryImpl callbackRegistry;
|
||||
private final CallbackRegistryImplementor callbackRegistry;
|
||||
private final EventListenerGroupImpl[] registeredEventListeners;
|
||||
private CallbackBuilder callbackBuilder;
|
||||
|
||||
|
@ -110,20 +110,16 @@ public class EventListenerRegistryImpl implements EventListenerRegistry, Stoppab
|
|||
ServiceRegistryImplementor registry) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
this.callbackRegistry = new CallbackRegistryImpl();
|
||||
this.callbackRegistry = CallbacksFactory.buildCallbackRegistry( sessionFactory );
|
||||
|
||||
this.registeredEventListeners = buildListenerGroups();
|
||||
}
|
||||
|
||||
EventListenerRegistryImpl(BootstrapContext bootstrapContext, SessionFactoryImplementor sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
|
||||
this.callbackRegistry = new CallbackRegistryImpl();
|
||||
this.callbackBuilder = new CallbackBuilderLegacyImpl(
|
||||
bootstrapContext.getServiceRegistry().getService( ManagedBeanRegistry.class ),
|
||||
bootstrapContext.getReflectionManager()
|
||||
);
|
||||
|
||||
this.callbackRegistry = CallbacksFactory.buildCallbackRegistry( sessionFactory );
|
||||
this.callbackBuilder = CallbacksFactory.buildCallbackBuilder(
|
||||
sessionFactory, bootstrapContext.getReflectionManager() );
|
||||
this.registeredEventListeners = buildListenerGroups();
|
||||
}
|
||||
|
||||
|
@ -131,7 +127,7 @@ public class EventListenerRegistryImpl implements EventListenerRegistry, Stoppab
|
|||
return sessionFactory;
|
||||
}
|
||||
|
||||
CallbackRegistryImpl getCallbackRegistry() {
|
||||
CallbackRegistry getCallbackRegistry() {
|
||||
return callbackRegistry;
|
||||
}
|
||||
|
||||
|
@ -139,9 +135,7 @@ public class EventListenerRegistryImpl implements EventListenerRegistry, Stoppab
|
|||
public void prepare(MetadataImplementor metadata) {
|
||||
if ( callbackBuilder == null ) {
|
||||
// TODO : not needed anymore when the deprecate constructor will be removed
|
||||
this.callbackBuilder = new CallbackBuilderLegacyImpl(
|
||||
sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class ),
|
||||
metadata.getMetadataBuildingOptions().getReflectionManager()
|
||||
this.callbackBuilder = CallbacksFactory.buildCallbackBuilder( sessionFactory, metadata.getMetadataBuildingOptions().getReflectionManager()
|
||||
);
|
||||
}
|
||||
for ( PersistentClass persistentClass : metadata.getEntityBindings() ) {
|
||||
|
|
|
@ -40,13 +40,13 @@ import org.jboss.logging.Logger;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CallbackBuilderLegacyImpl implements CallbackBuilder {
|
||||
final class CallbackBuilderLegacyImpl implements CallbackBuilder {
|
||||
private static final Logger log = Logger.getLogger( CallbackBuilderLegacyImpl.class );
|
||||
|
||||
private final ManagedBeanRegistry managedBeanRegistry;
|
||||
private final ReflectionManager reflectionManager;
|
||||
|
||||
public CallbackBuilderLegacyImpl(ManagedBeanRegistry managedBeanRegistry, ReflectionManager reflectionManager) {
|
||||
CallbackBuilderLegacyImpl(ManagedBeanRegistry managedBeanRegistry, ReflectionManager reflectionManager) {
|
||||
this.managedBeanRegistry = managedBeanRegistry;
|
||||
this.reflectionManager = reflectionManager;
|
||||
}
|
||||
|
|
|
@ -11,9 +11,7 @@ import javax.persistence.PersistenceException;
|
|||
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.jpa.event.spi.Callback;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||
import org.hibernate.jpa.event.spi.CallbackType;
|
||||
import org.hibernate.jpa.event.spi.CallbackBuilder;
|
||||
|
||||
/**
|
||||
* Keep track of all lifecycle callbacks and listeners for a given persistence unit
|
||||
|
@ -22,7 +20,7 @@ import org.hibernate.jpa.event.spi.CallbackBuilder;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@SuppressWarnings({"unchecked", "serial"})
|
||||
public class CallbackRegistryImpl implements CallbackRegistry, CallbackBuilder.CallbackRegistrar {
|
||||
final class CallbackRegistryImpl implements CallbackRegistryImplementor {
|
||||
private HashMap<Class, Callback[]> preCreates = new HashMap<Class, Callback[]>();
|
||||
private HashMap<Class, Callback[]> postCreates = new HashMap<Class, Callback[]>();
|
||||
private HashMap<Class, Callback[]> preRemoves = new HashMap<Class, Callback[]>();
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.event.internal;
|
||||
|
||||
import org.hibernate.jpa.event.spi.CallbackBuilder;
|
||||
import org.hibernate.jpa.event.spi.CallbackRegistry;
|
||||
|
||||
public interface CallbackRegistryImplementor extends CallbackRegistry, CallbackBuilder.CallbackRegistrar {
|
||||
|
||||
void release();
|
||||
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.jpa.event.internal;
|
||||
|
||||
import org.hibernate.annotations.common.reflection.ReflectionManager;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.jpa.event.spi.CallbackBuilder;
|
||||
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
|
||||
|
||||
/**
|
||||
* The intent of this class is to use a lighter implementation
|
||||
* when JPA callbacks are disabled via
|
||||
* {@link org.hibernate.boot.spi.SessionFactoryOptions#areJPACallbacksEnabled()}
|
||||
*/
|
||||
public final class CallbacksFactory {
|
||||
|
||||
public static CallbackRegistryImplementor buildCallbackRegistry(SessionFactoryImplementor sessionFactory) {
|
||||
if ( jpaCallBacksEnabled( sessionFactory ) ) {
|
||||
return new CallbackRegistryImpl();
|
||||
}
|
||||
else {
|
||||
return new EmptyCallbackRegistryImpl();
|
||||
}
|
||||
}
|
||||
|
||||
public static CallbackBuilder buildCallbackBuilder(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
ReflectionManager reflectionManager) {
|
||||
if ( jpaCallBacksEnabled( sessionFactory ) ) {
|
||||
final ManagedBeanRegistry managedBeanRegistry = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
|
||||
return new CallbackBuilderLegacyImpl(
|
||||
managedBeanRegistry,
|
||||
reflectionManager
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new EmptyCallbackBuilder();
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean jpaCallBacksEnabled(SessionFactoryImplementor sessionFactory) {
|
||||
SessionFactoryOptions options = sessionFactory.getSessionFactoryOptions();
|
||||
return options.areJPACallbacksEnabled();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.jpa.event.internal;
|
||||
|
||||
import org.hibernate.jpa.event.spi.CallbackBuilder;
|
||||
import org.hibernate.mapping.Property;
|
||||
|
||||
final class EmptyCallbackBuilder implements CallbackBuilder {
|
||||
|
||||
@Override
|
||||
public void buildCallbacksForEntity(String entityClassName, CallbackRegistrar callbackRegistrar) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildCallbacksForEmbeddable(Property embeddableProperty, String entityClassName, CallbackRegistrar callbackRegistrar) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
//no-op
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.jpa.event.internal;
|
||||
|
||||
import org.hibernate.jpa.event.spi.Callback;
|
||||
import org.hibernate.jpa.event.spi.CallbackType;
|
||||
|
||||
final class EmptyCallbackRegistryImpl implements CallbackRegistryImplementor {
|
||||
|
||||
@Override
|
||||
public boolean hasRegisteredCallbacks(final Class entityClass, final CallbackType callbackType) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preCreate(final Object entity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postCreate(final Object entity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preUpdate(final Object entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postUpdate(final Object entity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preRemove(final Object entity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postRemove(final Object entity) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean postLoad(final Object entity) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPostCreateCallbacks(final Class entityClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPostUpdateCallbacks(final Class entityClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPostRemoveCallbacks(final Class entityClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasRegisteredCallbacks(final Class entityClass, final Class annotationClass) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
//no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerCallbacks(Class entityClass, Callback[] callbacks) {
|
||||
//no-op
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.jpa.test.callbacks;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.Map;
|
||||
import javax.persistence.EntityManager;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.jpa.test.Cat;
|
||||
import org.hibernate.jpa.test.Kitten;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Sanne Grinovero
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CallbacksDisabledTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Test
|
||||
public void testCallbacksAreDisabled() throws Exception {
|
||||
EntityManager em = getOrCreateEntityManager();
|
||||
Cat c = new Cat();
|
||||
c.setName( "Kitty" );
|
||||
c.setDateOfBirth( new Date( 90, 11, 15 ) );
|
||||
em.getTransaction().begin();
|
||||
em.persist( c );
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
em.getTransaction().begin();
|
||||
c = em.find( Cat.class, c.getId() );
|
||||
assertTrue( c.getAge() == 0 ); // With listeners enabled this would be false. Proven by org.hibernate.jpa.test.callbacks.CallbacksTest.testCallbackMethod
|
||||
em.getTransaction().commit();
|
||||
em.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[]{
|
||||
Cat.class,
|
||||
Translation.class,
|
||||
Television.class,
|
||||
RemoteControl.class,
|
||||
Rythm.class,
|
||||
Plant.class,
|
||||
Kitten.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( AvailableSettings.JPA_CALLBACKS_ENABLED, "false" );
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue