HHH-17955 Bean Validation and @PostXxxx callbacks for StatelessSession

Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
Gavin King 2024-04-13 20:09:02 +02:00
parent 59603dffb3
commit 9a4d21d71d
41 changed files with 730 additions and 177 deletions

View File

@ -239,18 +239,19 @@ public class EntityInsertAction extends AbstractEntityInsertAction {
} }
protected boolean preInsert() { protected boolean preInsert() {
boolean veto = false;
final EventListenerGroup<PreInsertEventListener> listenerGroup final EventListenerGroup<PreInsertEventListener> listenerGroup
= getFastSessionServices().eventListenerGroup_PRE_INSERT; = getFastSessionServices().eventListenerGroup_PRE_INSERT;
if ( listenerGroup.isEmpty() ) { if ( listenerGroup.isEmpty() ) {
return false;
}
else {
boolean veto = false;
final PreInsertEvent event = new PreInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() );
for ( PreInsertEventListener listener : listenerGroup.listeners() ) {
veto |= listener.onPreInsert( event );
}
return veto; return veto;
} }
final PreInsertEvent event = new PreInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() );
for ( PreInsertEventListener listener : listenerGroup.listeners() ) {
veto |= listener.onPreInsert( event );
}
return veto;
} }
@Override @Override

View File

@ -20,6 +20,8 @@ import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener; import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.PreUpdateEvent; import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener; import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.event.spi.PreUpsertEvent;
import org.hibernate.event.spi.PreUpsertEventListener;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.RepresentationMode;
@ -42,7 +44,7 @@ import jakarta.validation.ValidatorFactory;
*/ */
//FIXME review exception model //FIXME review exception model
public class BeanValidationEventListener public class BeanValidationEventListener
implements PreInsertEventListener, PreUpdateEventListener, PreDeleteEventListener { implements PreInsertEventListener, PreUpdateEventListener, PreDeleteEventListener, PreUpsertEventListener {
private static final CoreMessageLogger LOG = Logger.getMessageLogger( private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class, CoreMessageLogger.class,
@ -60,7 +62,8 @@ public class BeanValidationEventListener
* @param factory The {@code ValidatorFactory} to use to create {@code Validator} instance(s) * @param factory The {@code ValidatorFactory} to use to create {@code Validator} instance(s)
* @param settings Configured properties * @param settings Configured properties
*/ */
public BeanValidationEventListener(ValidatorFactory factory, Map<String,Object> settings, ClassLoaderService classLoaderService) { public BeanValidationEventListener(
ValidatorFactory factory, Map<String,Object> settings, ClassLoaderService classLoaderService) {
init( factory, settings, classLoaderService ); init( factory, settings, classLoaderService );
} }
@ -80,9 +83,8 @@ public class BeanValidationEventListener
public boolean onPreInsert(PreInsertEvent event) { public boolean onPreInsert(PreInsertEvent event) {
validate( validate(
event.getEntity(), event.getEntity(),
event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(), event.getPersister(),
event.getSession().getFactory(), event.getFactory(),
GroupsPerOperation.Operation.INSERT GroupsPerOperation.Operation.INSERT
); );
return false; return false;
@ -91,9 +93,8 @@ public class BeanValidationEventListener
public boolean onPreUpdate(PreUpdateEvent event) { public boolean onPreUpdate(PreUpdateEvent event) {
validate( validate(
event.getEntity(), event.getEntity(),
event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(), event.getPersister(),
event.getSession().getFactory(), event.getFactory(),
GroupsPerOperation.Operation.UPDATE GroupsPerOperation.Operation.UPDATE
); );
return false; return false;
@ -102,21 +103,30 @@ public class BeanValidationEventListener
public boolean onPreDelete(PreDeleteEvent event) { public boolean onPreDelete(PreDeleteEvent event) {
validate( validate(
event.getEntity(), event.getEntity(),
event.getPersister().getRepresentationStrategy().getMode(),
event.getPersister(), event.getPersister(),
event.getSession().getFactory(), event.getFactory(),
GroupsPerOperation.Operation.DELETE GroupsPerOperation.Operation.DELETE
); );
return false; return false;
} }
@Override
public boolean onPreUpsert(PreUpsertEvent event) {
validate(
event.getEntity(),
event.getPersister(),
event.getFactory(),
GroupsPerOperation.Operation.UPSERT
);
return false;
}
private <T> void validate( private <T> void validate(
T object, T object,
RepresentationMode mode,
EntityPersister persister, EntityPersister persister,
SessionFactoryImplementor sessionFactory, SessionFactoryImplementor sessionFactory,
GroupsPerOperation.Operation operation) { GroupsPerOperation.Operation operation) {
if ( object == null || mode != RepresentationMode.POJO ) { if ( object == null || persister.getRepresentationStrategy().getMode() != RepresentationMode.POJO ) {
return; return;
} }
TraversableResolver tr = new HibernateTraversableResolver( persister, associationsPerEntityPersister, sessionFactory ); TraversableResolver tr = new HibernateTraversableResolver( persister, associationsPerEntityPersister, sessionFactory );

View File

@ -39,6 +39,7 @@ public class GroupsPerOperation {
applyOperationGrouping( groupsPerOperation, Operation.INSERT, settings, classLoaderAccess ); applyOperationGrouping( groupsPerOperation, Operation.INSERT, settings, classLoaderAccess );
applyOperationGrouping( groupsPerOperation, Operation.UPDATE, settings, classLoaderAccess ); applyOperationGrouping( groupsPerOperation, Operation.UPDATE, settings, classLoaderAccess );
applyOperationGrouping( groupsPerOperation, Operation.DELETE, settings, classLoaderAccess ); applyOperationGrouping( groupsPerOperation, Operation.DELETE, settings, classLoaderAccess );
applyOperationGrouping( groupsPerOperation, Operation.UPSERT, settings, classLoaderAccess );
applyOperationGrouping( groupsPerOperation, Operation.DDL, settings, classLoaderAccess ); applyOperationGrouping( groupsPerOperation, Operation.DDL, settings, classLoaderAccess );
return groupsPerOperation; return groupsPerOperation;
@ -99,10 +100,11 @@ public class GroupsPerOperation {
return groupsPerOperation.get( operation ); return groupsPerOperation.get( operation );
} }
public static enum Operation { public enum Operation {
INSERT( "persist", JPA_GROUP_PREFIX + "pre-persist", JAKARTA_JPA_GROUP_PREFIX + "pre-persist" ), INSERT( "persist", JPA_GROUP_PREFIX + "pre-persist", JAKARTA_JPA_GROUP_PREFIX + "pre-persist" ),
UPDATE( "update", JPA_GROUP_PREFIX + "pre-update", JAKARTA_JPA_GROUP_PREFIX + "pre-update" ), UPDATE( "update", JPA_GROUP_PREFIX + "pre-update", JAKARTA_JPA_GROUP_PREFIX + "pre-update" ),
DELETE( "remove", JPA_GROUP_PREFIX + "pre-remove", JAKARTA_JPA_GROUP_PREFIX + "pre-remove" ), DELETE( "remove", JPA_GROUP_PREFIX + "pre-remove", JAKARTA_JPA_GROUP_PREFIX + "pre-remove" ),
UPSERT( "upsert", JPA_GROUP_PREFIX + "pre-upsert", JAKARTA_JPA_GROUP_PREFIX + "pre-upsert" ),
DDL( "ddl", HIBERNATE_GROUP_PREFIX + "ddl", HIBERNATE_GROUP_PREFIX + "ddl" ); DDL( "ddl", HIBERNATE_GROUP_PREFIX + "ddl", HIBERNATE_GROUP_PREFIX + "ddl" );

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.boot.beanvalidation; package org.hibernate.boot.beanvalidation;
import java.lang.annotation.Annotation;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -23,8 +24,6 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.config.spi.StandardConverters;
@ -40,6 +39,7 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.SingleTableSubclass; import org.hibernate.mapping.SingleTableSubclass;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import jakarta.validation.Validation; import jakarta.validation.Validation;
@ -48,6 +48,11 @@ import jakarta.validation.metadata.BeanDescriptor;
import jakarta.validation.metadata.ConstraintDescriptor; import jakarta.validation.metadata.ConstraintDescriptor;
import jakarta.validation.metadata.PropertyDescriptor; import jakarta.validation.metadata.PropertyDescriptor;
import static org.hibernate.boot.beanvalidation.GroupsPerOperation.buildGroupsForOperation;
import static org.hibernate.cfg.ValidationSettings.CHECK_NULLABILITY;
import static org.hibernate.cfg.ValidationSettings.JAKARTA_VALIDATION_FACTORY;
import static org.hibernate.cfg.ValidationSettings.JPA_VALIDATION_FACTORY;
/** /**
* @author Emmanuel Bernard * @author Emmanuel Bernard
* @author Hardy Ferentschik * @author Hardy Ferentschik
@ -62,7 +67,7 @@ class TypeSafeActivator {
* *
* @param object The supplied ValidatorFactory instance. * @param object The supplied ValidatorFactory instance.
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings("UnusedDeclaration")
public static void validateSuppliedFactory(Object object) { public static void validateSuppliedFactory(Object object) {
if ( !(object instanceof ValidatorFactory) ) { if ( !(object instanceof ValidatorFactory) ) {
throw new IntegrationException( throw new IntegrationException(
@ -95,49 +100,46 @@ class TypeSafeActivator {
applyCallbackListeners( factory, activationContext ); applyCallbackListeners( factory, activationContext );
} }
@SuppressWarnings( {"UnusedDeclaration"})
public static void applyCallbackListeners(ValidatorFactory validatorFactory, ActivationContext activationContext) { public static void applyCallbackListeners(ValidatorFactory validatorFactory, ActivationContext activationContext) {
final Set<ValidationMode> modes = activationContext.getValidationModes(); final Set<ValidationMode> modes = activationContext.getValidationModes();
if ( ! ( modes.contains( ValidationMode.CALLBACK ) || modes.contains( ValidationMode.AUTO ) ) ) { if ( !modes.contains( ValidationMode.CALLBACK ) && !modes.contains( ValidationMode.AUTO ) ) {
return; return;
} }
final ConfigurationService cfgService = activationContext.getServiceRegistry().requireService( ConfigurationService.class ); final SessionFactoryServiceRegistry serviceRegistry = activationContext.getServiceRegistry();
final ClassLoaderService classLoaderService = activationContext.getServiceRegistry().requireService( ClassLoaderService.class ); final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
final EventListenerRegistry listenerRegistry = serviceRegistry.requireService( EventListenerRegistry.class );
// de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly // de-activate not-null tracking at the core level when Bean Validation is present unless the user explicitly
// asks for it // asks for it
if ( cfgService.getSettings().get( Environment.CHECK_NULLABILITY ) == null ) { if ( cfgService.getSettings().get( CHECK_NULLABILITY ) == null ) {
activationContext.getSessionFactory().getSessionFactoryOptions().setCheckNullability( false ); activationContext.getSessionFactory().getSessionFactoryOptions().setCheckNullability( false );
} }
final BeanValidationEventListener listener = new BeanValidationEventListener( final BeanValidationEventListener listener =
validatorFactory, new BeanValidationEventListener( validatorFactory, cfgService.getSettings(), classLoaderService );
cfgService.getSettings(),
classLoaderService
);
final EventListenerRegistry listenerRegistry = activationContext.getServiceRegistry()
.requireService( EventListenerRegistry.class );
listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE ); listenerRegistry.addDuplicationStrategy( DuplicationStrategyImpl.INSTANCE );
listenerRegistry.appendListeners( EventType.PRE_INSERT, listener ); listenerRegistry.appendListeners( EventType.PRE_INSERT, listener );
listenerRegistry.appendListeners( EventType.PRE_UPDATE, listener ); listenerRegistry.appendListeners( EventType.PRE_UPDATE, listener );
listenerRegistry.appendListeners( EventType.PRE_DELETE, listener ); listenerRegistry.appendListeners( EventType.PRE_DELETE, listener );
listenerRegistry.appendListeners( EventType.PRE_UPSERT, listener );
listener.initialize( cfgService.getSettings(), classLoaderService ); listener.initialize( cfgService.getSettings(), classLoaderService );
} }
private static void applyRelationalConstraints(ValidatorFactory factory, ActivationContext activationContext) { private static void applyRelationalConstraints(ValidatorFactory factory, ActivationContext activationContext) {
final ConfigurationService cfgService = activationContext.getServiceRegistry().requireService( ConfigurationService.class ); final SessionFactoryServiceRegistry serviceRegistry = activationContext.getServiceRegistry();
final ConfigurationService cfgService = serviceRegistry.requireService( ConfigurationService.class );
if ( !cfgService.getSetting( BeanValidationIntegrator.APPLY_CONSTRAINTS, StandardConverters.BOOLEAN, true ) ) { if ( !cfgService.getSetting( BeanValidationIntegrator.APPLY_CONSTRAINTS, StandardConverters.BOOLEAN, true ) ) {
LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" ); LOG.debug( "Skipping application of relational constraints from legacy Hibernate Validator" );
return; return;
} }
final Set<ValidationMode> modes = activationContext.getValidationModes(); final Set<ValidationMode> modes = activationContext.getValidationModes();
if ( ! ( modes.contains( ValidationMode.DDL ) || modes.contains( ValidationMode.AUTO ) ) ) { if ( !modes.contains( ValidationMode.DDL ) && !modes.contains( ValidationMode.AUTO ) ) {
return; return;
} }
@ -145,32 +147,25 @@ class TypeSafeActivator {
factory, factory,
activationContext.getMetadata().getEntityBindings(), activationContext.getMetadata().getEntityBindings(),
cfgService.getSettings(), cfgService.getSettings(),
activationContext.getServiceRegistry().requireService( JdbcServices.class ).getDialect(), serviceRegistry.requireService( JdbcServices.class ).getDialect(),
new ClassLoaderAccessImpl( new ClassLoaderAccessImpl( null,
null, serviceRegistry.getService( ClassLoaderService.class ) )
activationContext.getServiceRegistry().getService( ClassLoaderService.class )
)
); );
} }
@SuppressWarnings( {"UnusedDeclaration"})
public static void applyRelationalConstraints( public static void applyRelationalConstraints(
ValidatorFactory factory, ValidatorFactory factory,
Collection<PersistentClass> persistentClasses, Collection<PersistentClass> persistentClasses,
Map<String,Object> settings, Map<String,Object> settings,
Dialect dialect, Dialect dialect,
ClassLoaderAccess classLoaderAccess) { ClassLoaderAccess classLoaderAccess) {
Class<?>[] groupsArray = GroupsPerOperation.buildGroupsForOperation( final Class<?>[] groupsArray =
GroupsPerOperation.Operation.DDL, buildGroupsForOperation( GroupsPerOperation.Operation.DDL, settings, classLoaderAccess );
settings, final Set<Class<?>> groups = new HashSet<>( Arrays.asList( groupsArray ) );
classLoaderAccess
);
Set<Class<?>> groups = new HashSet<>( Arrays.asList( groupsArray ) );
for ( PersistentClass persistentClass : persistentClasses ) { for ( PersistentClass persistentClass : persistentClasses ) {
final String className = persistentClass.getClassName(); final String className = persistentClass.getClassName();
if ( className == null || className.isEmpty() ) {
if ( className == null || className.length() == 0 ) {
continue; continue;
} }
Class<?> clazz; Class<?> clazz;
@ -202,17 +197,21 @@ class TypeSafeActivator {
//no bean level constraints can be applied, go to the properties //no bean level constraints can be applied, go to the properties
for ( PropertyDescriptor propertyDesc : descriptor.getConstrainedProperties() ) { for ( PropertyDescriptor propertyDesc : descriptor.getConstrainedProperties() ) {
Property property = findPropertyByName( persistentClass, prefix + propertyDesc.getPropertyName() ); final Property property =
boolean hasNotNull; findPropertyByName( persistentClass, prefix + propertyDesc.getPropertyName() );
if ( property != null ) { if ( property != null ) {
hasNotNull = applyConstraints( final boolean hasNotNull = applyConstraints(
propertyDesc.getConstraintDescriptors(), property, propertyDesc, groups, activateNotNull, dialect propertyDesc.getConstraintDescriptors(),
property,
propertyDesc,
groups,
activateNotNull,
dialect
); );
if ( property.isComposite() && propertyDesc.isCascaded() ) { if ( property.isComposite() && propertyDesc.isCascaded() ) {
Class<?> componentClass = ( (Component) property.getValue() ).getComponentClass(); final Component component = (Component) property.getValue();
/* /*
* we can apply not null if the upper component let's us activate not null * we can apply not null if the upper component lets us activate not null
* and if the property is not null. * and if the property is not null.
* Otherwise, all sub columns should be left nullable * Otherwise, all sub columns should be left nullable
*/ */
@ -220,7 +219,7 @@ class TypeSafeActivator {
applyDDL( applyDDL(
prefix + propertyDesc.getPropertyName() + ".", prefix + propertyDesc.getPropertyName() + ".",
persistentClass, persistentClass,
componentClass, component.getComponentClass(),
factory, factory,
groups, groups,
canSetNotNullOnColumns, canSetNotNullOnColumns,
@ -275,8 +274,8 @@ class TypeSafeActivator {
private static void applyMin(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) { private static void applyMin(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) {
if ( Min.class.equals( descriptor.getAnnotation().annotationType() ) ) { if ( Min.class.equals( descriptor.getAnnotation().annotationType() ) ) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ConstraintDescriptor<Min> minConstraint = (ConstraintDescriptor<Min>) descriptor; final ConstraintDescriptor<Min> minConstraint = (ConstraintDescriptor<Min>) descriptor;
long min = minConstraint.getAnnotation().value(); final long min = minConstraint.getAnnotation().value();
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column ) { if ( selectable instanceof Column ) {
@ -291,8 +290,8 @@ class TypeSafeActivator {
private static void applyMax(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) { private static void applyMax(Property property, ConstraintDescriptor<?> descriptor, Dialect dialect) {
if ( Max.class.equals( descriptor.getAnnotation().annotationType() ) ) { if ( Max.class.equals( descriptor.getAnnotation().annotationType() ) ) {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
ConstraintDescriptor<Max> maxConstraint = (ConstraintDescriptor<Max>) descriptor; final ConstraintDescriptor<Max> maxConstraint = (ConstraintDescriptor<Max>) descriptor;
long max = maxConstraint.getAnnotation().value(); final long max = maxConstraint.getAnnotation().value();
for ( Selectable selectable : property.getSelectables() ) { for ( Selectable selectable : property.getSelectables() ) {
if ( selectable instanceof Column ) { if ( selectable instanceof Column ) {
@ -318,9 +317,10 @@ class TypeSafeActivator {
private static boolean applyNotNull(Property property, ConstraintDescriptor<?> descriptor) { private static boolean applyNotNull(Property property, ConstraintDescriptor<?> descriptor) {
boolean hasNotNull = false; boolean hasNotNull = false;
// NotNull, NotEmpty, and NotBlank annotation add not-null on column // NotNull, NotEmpty, and NotBlank annotation add not-null on column
if ( NotNull.class.equals( descriptor.getAnnotation().annotationType()) final Class<? extends Annotation> annotationType = descriptor.getAnnotation().annotationType();
|| NotEmpty.class.equals( descriptor.getAnnotation().annotationType()) if ( NotNull.class.equals(annotationType)
|| NotBlank.class.equals( descriptor.getAnnotation().annotationType())) { || NotEmpty.class.equals(annotationType)
|| NotBlank.class.equals(annotationType)) {
// single table inheritance should not be forced to null due to shared state // single table inheritance should not be forced to null due to shared state
if ( !( property.getPersistentClass() instanceof SingleTableSubclass ) ) { if ( !( property.getPersistentClass() instanceof SingleTableSubclass ) ) {
//composite should not add not-null on all columns //composite should not add not-null on all columns
@ -406,7 +406,7 @@ class TypeSafeActivator {
String idName = idProperty != null ? idProperty.getName() : null; String idName = idProperty != null ? idProperty.getName() : null;
try { try {
if ( propertyName == null if ( propertyName == null
|| propertyName.length() == 0 || propertyName.isEmpty()
|| propertyName.equals( idName ) ) { || propertyName.equals( idName ) ) {
//default to id //default to id
property = idProperty; property = idProperty;
@ -488,11 +488,9 @@ class TypeSafeActivator {
private static ValidatorFactory resolveProvidedFactory(SessionFactoryOptions options) { private static ValidatorFactory resolveProvidedFactory(SessionFactoryOptions options) {
final Object validatorFactoryReference = options.getValidatorFactoryReference(); final Object validatorFactoryReference = options.getValidatorFactoryReference();
if ( validatorFactoryReference == null ) { if ( validatorFactoryReference == null ) {
return null; return null;
} }
try { try {
return (ValidatorFactory) validatorFactoryReference; return (ValidatorFactory) validatorFactoryReference;
} }
@ -511,7 +509,7 @@ class TypeSafeActivator {
private static ValidatorFactory resolveProvidedFactory(ConfigurationService cfgService) { private static ValidatorFactory resolveProvidedFactory(ConfigurationService cfgService) {
return cfgService.getSetting( return cfgService.getSetting(
AvailableSettings.JPA_VALIDATION_FACTORY, JPA_VALIDATION_FACTORY,
value -> { value -> {
try { try {
return (ValidatorFactory) value; return (ValidatorFactory) value;
@ -521,7 +519,7 @@ class TypeSafeActivator {
String.format( String.format(
Locale.ENGLISH, Locale.ENGLISH,
"ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s", "ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s",
AvailableSettings.JPA_VALIDATION_FACTORY, JPA_VALIDATION_FACTORY,
ValidatorFactory.class.getName(), ValidatorFactory.class.getName(),
value.getClass().getName() value.getClass().getName()
) )
@ -529,7 +527,7 @@ class TypeSafeActivator {
} }
}, },
cfgService.getSetting( cfgService.getSetting(
AvailableSettings.JAKARTA_VALIDATION_FACTORY, JAKARTA_VALIDATION_FACTORY,
value -> { value -> {
try { try {
return (ValidatorFactory) value; return (ValidatorFactory) value;
@ -539,7 +537,7 @@ class TypeSafeActivator {
String.format( String.format(
Locale.ENGLISH, Locale.ENGLISH,
"ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s", "ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s",
AvailableSettings.JAKARTA_VALIDATION_FACTORY, JAKARTA_VALIDATION_FACTORY,
ValidatorFactory.class.getName(), ValidatorFactory.class.getName(),
value.getClass().getName() value.getClass().getName()
) )

View File

@ -10,14 +10,12 @@ import java.util.Set;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.action.internal.CollectionAction; import org.hibernate.action.internal.CollectionAction;
import org.hibernate.action.spi.AfterTransactionCompletionProcess;
import org.hibernate.boot.Metadata; import org.hibernate.boot.Metadata;
import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.boot.spi.SessionFactoryOptions;
import org.hibernate.cache.spi.access.CollectionDataAccess; import org.hibernate.cache.spi.access.CollectionDataAccess;
import org.hibernate.cache.spi.access.SoftLock; import org.hibernate.cache.spi.access.SoftLock;
import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.collection.spi.PersistentCollection;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.EventType;

View File

@ -22,7 +22,6 @@ import java.io.ObjectOutputStream;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection; import java.util.Collection;
import org.checkerframework.checker.initialization.qual.UnderInitialization;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
/** /**

View File

@ -115,18 +115,19 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
} }
final EventSource session = event.getSession(); final EventSource session = event.getSession();
final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final ActionQueue actionQueue = session.getActionQueue();
LOG.debugf( LOG.debugf(
"Flushed: %s insertions, %s updates, %s deletions to %s objects", "Flushed: %s insertions, %s updates, %s deletions to %s objects",
session.getActionQueue().numberOfInsertions(), actionQueue.numberOfInsertions(),
session.getActionQueue().numberOfUpdates(), actionQueue.numberOfUpdates(),
session.getActionQueue().numberOfDeletions(), actionQueue.numberOfDeletions(),
persistenceContext.getNumberOfManagedEntities() persistenceContext.getNumberOfManagedEntities()
); );
LOG.debugf( LOG.debugf(
"Flushed: %s (re)creations, %s updates, %s removals to %s collections", "Flushed: %s (re)creations, %s updates, %s removals to %s collections",
session.getActionQueue().numberOfCollectionCreations(), actionQueue.numberOfCollectionCreations(),
session.getActionQueue().numberOfCollectionUpdates(), actionQueue.numberOfCollectionUpdates(),
session.getActionQueue().numberOfCollectionRemovals(), actionQueue.numberOfCollectionRemovals(),
persistenceContext.getCollectionEntriesSize() persistenceContext.getCollectionEntriesSize()
); );
new EntityPrinter( session.getFactory() ).toString( new EntityPrinter( session.getFactory() ).toString(
@ -205,8 +206,8 @@ public abstract class AbstractFlushingEventListener implements JpaBootstrapSensi
LOG.trace( "Flushing entities and processing referenced collections" ); LOG.trace( "Flushing entities and processing referenced collections" );
final EventSource source = event.getSession(); final EventSource source = event.getSession();
final EventListenerGroup<FlushEntityEventListener> flushListeners = source.getFactory() final EventListenerGroup<FlushEntityEventListener> flushListeners =
.getFastSessionServices().eventListenerGroup_FLUSH_ENTITY; event.getFactory().getFastSessionServices().eventListenerGroup_FLUSH_ENTITY;
// Among other things, updateReachables() will recursively load all // Among other things, updateReachables() will recursively load all
// collections that are moving roles. This might cause entities to // collections that are moving roles. This might cause entities to

View File

@ -47,7 +47,7 @@ public abstract class AbstractReassociateEventListener {
if ( log.isTraceEnabled() ) { if ( log.isTraceEnabled() ) {
log.tracev( log.tracev(
"Reassociating transient instance: {0}", "Reassociating transient instance: {0}",
MessageHelper.infoString( persister, id, event.getSession().getFactory() ) MessageHelper.infoString( persister, id, event.getFactory() )
); );
} }

View File

@ -20,7 +20,6 @@ import org.hibernate.engine.spi.CascadingAction;
import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityEntryExtraState; import org.hibernate.engine.spi.EntityEntryExtraState;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.ManagedEntity;
import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.SelfDirtinessTracker;
import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SessionImplementor;

View File

@ -104,7 +104,7 @@ public class DefaultDeleteEventListener implements DeleteEventListener, Callback
if ( lazyInitializer != null ) { if ( lazyInitializer != null ) {
if ( lazyInitializer.isUninitialized() ) { if ( lazyInitializer.isUninitialized() ) {
final EventSource source = event.getSession(); final EventSource source = event.getSession();
final EntityPersister persister = source.getFactory().getMappingMetamodel() final EntityPersister persister = event.getFactory().getMappingMetamodel()
.findEntityDescriptor( lazyInitializer.getEntityName() ); .findEntityDescriptor( lazyInitializer.getEntityName() );
final Object id = lazyInitializer.getIdentifier(); final Object id = lazyInitializer.getIdentifier();
final EntityKey key = source.generateEntityKey( id, persister ); final EntityKey key = source.generateEntityKey( id, persister );

View File

@ -223,10 +223,9 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
final Object entity = event.getEntity(); final Object entity = event.getEntity();
processIfSelfDirtinessTracker( entity, SelfDirtinessTracker::$$_hibernate_clearDirtyAttributes ); processIfSelfDirtinessTracker( entity, SelfDirtinessTracker::$$_hibernate_clearDirtyAttributes );
processIfManagedEntity( entity, DefaultFlushEntityEventListener::useTracker ); processIfManagedEntity( entity, DefaultFlushEntityEventListener::useTracker );
final EventSource source = event.getSession(); event.getFactory()
source.getFactory()
.getCustomEntityDirtinessStrategy() .getCustomEntityDirtinessStrategy()
.resetDirty( entity, entry.getPersister(), source ); .resetDirty( entity, entry.getPersister(), event.getSession() );
return false; return false;
} }
} }
@ -247,7 +246,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
final EntityPersister persister = entry.getPersister(); final EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues(); final Object[] values = event.getPropertyValues();
logScheduleUpdate( entry, session, status, persister ); logScheduleUpdate( entry, event.getFactory(), status, persister );
final boolean intercepted = !entry.isBeingReplicated() && handleInterception( event ); final boolean intercepted = !entry.isBeingReplicated() && handleInterception( event );
@ -299,32 +298,32 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
} }
} }
private static void logScheduleUpdate(EntityEntry entry, EventSource session, Status status, EntityPersister persister) { private static void logScheduleUpdate(EntityEntry entry, SessionFactoryImplementor factory, Status status, EntityPersister persister) {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
if ( status == Status.DELETED ) { if ( status == Status.DELETED ) {
if ( !persister.isMutable() ) { if ( !persister.isMutable() ) {
LOG.tracev( LOG.tracev(
"Updating immutable, deleted entity: {0}", "Updating immutable, deleted entity: {0}",
MessageHelper.infoString(persister, entry.getId(), session.getFactory() ) MessageHelper.infoString(persister, entry.getId(), factory)
); );
} }
else if ( !entry.isModifiableEntity() ) { else if ( !entry.isModifiableEntity() ) {
LOG.tracev( LOG.tracev(
"Updating non-modifiable, deleted entity: {0}", "Updating non-modifiable, deleted entity: {0}",
MessageHelper.infoString(persister, entry.getId(), session.getFactory() ) MessageHelper.infoString(persister, entry.getId(), factory)
); );
} }
else { else {
LOG.tracev( LOG.tracev(
"Updating deleted entity: {0}", "Updating deleted entity: {0}",
MessageHelper.infoString(persister, entry.getId(), session.getFactory() ) MessageHelper.infoString(persister, entry.getId(), factory)
); );
} }
} }
else { else {
LOG.tracev( LOG.tracev(
"Updating entity: {0}", "Updating entity: {0}",
MessageHelper.infoString(persister, entry.getId(), session.getFactory() ) MessageHelper.infoString(persister, entry.getId(), factory)
); );
} }
} }
@ -352,7 +351,7 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
if ( entry.getStatus() != Status.DELETED ) { if ( entry.getStatus() != Status.DELETED ) {
if ( callbackRegistry.preUpdate( entity ) ) { if ( callbackRegistry.preUpdate( entity ) ) {
isDirty = copyState( entity, persister.getPropertyTypes(), values, session.getFactory() ); isDirty = copyState( entity, persister.getPropertyTypes(), values, event.getFactory() );
} }
} }
@ -593,10 +592,9 @@ public class DefaultFlushEntityEventListener implements FlushEntityEventListener
} }
} }
} }
final EventSource session = event.getSession();
final DirtyCheckContextImpl context = new DirtyCheckContextImpl(); final DirtyCheckContextImpl context = new DirtyCheckContextImpl();
session.getFactory().getCustomEntityDirtinessStrategy() event.getFactory().getCustomEntityDirtinessStrategy()
.findDirty( event.getEntity(), event.getEntityEntry().getPersister(), session, context ); .findDirty( event.getEntity(), event.getEntityEntry().getPersister(), event.getSession(), context );
return context.found; return context.found;
} }

View File

@ -85,21 +85,19 @@ public class DefaultLoadEventListener implements LoadEventListener {
protected EntityPersister getPersister(final LoadEvent event) { protected EntityPersister getPersister(final LoadEvent event) {
final Object instanceToLoad = event.getInstanceToLoad(); final Object instanceToLoad = event.getInstanceToLoad();
final EventSource source = event.getSession();
if ( instanceToLoad != null ) { if ( instanceToLoad != null ) {
//the load() which takes an entity does not pass an entityName //the load() which takes an entity does not pass an entityName
event.setEntityClassName( instanceToLoad.getClass().getName() ); event.setEntityClassName( instanceToLoad.getClass().getName() );
return source.getEntityPersister( null, instanceToLoad ); return event.getSession().getEntityPersister( null, instanceToLoad );
} }
else { else {
return source.getFactory().getMappingMetamodel().getEntityDescriptor( event.getEntityClassName() ); return event.getFactory().getMappingMetamodel().getEntityDescriptor( event.getEntityClassName() );
} }
} }
private void doOnLoad(EntityPersister persister, LoadEvent event, LoadType loadType) { private void doOnLoad(EntityPersister persister, LoadEvent event, LoadType loadType) {
try { try {
final EventSource session = event.getSession(); final EntityKey keyToLoad = event.getSession().generateEntityKey( event.getEntityId(), persister );
final EntityKey keyToLoad = session.generateEntityKey( event.getEntityId(), persister );
if ( loadType.isNakedEntityReturned() ) { if ( loadType.isNakedEntityReturned() ) {
//do not return a proxy! //do not return a proxy!
//(this option indicates we are initializing a proxy) //(this option indicates we are initializing a proxy)
@ -193,22 +191,22 @@ public class DefaultLoadEventListener implements LoadEventListener {
* @return The loaded entity. * @return The loaded entity.
*/ */
private Object load(LoadEvent event, EntityPersister persister, EntityKey keyToLoad, LoadType options) { private Object load(LoadEvent event, EntityPersister persister, EntityKey keyToLoad, LoadType options) {
final EventSource session = event.getSession();
if ( event.getInstanceToLoad() != null ) { if ( event.getInstanceToLoad() != null ) {
final EventSource session = event.getSession();
if ( session.getPersistenceContextInternal().getEntry( event.getInstanceToLoad() ) != null ) { if ( session.getPersistenceContextInternal().getEntry( event.getInstanceToLoad() ) != null ) {
throw new PersistentObjectException( throw new PersistentObjectException(
"attempted to load into an instance that was already associated with the session: " "attempted to load into an instance that was already associated with the session: "
+ infoString( persister, event.getEntityId(), session.getFactory() ) + infoString( persister, event.getEntityId(), event.getFactory() )
); );
} }
persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), session); persister.setIdentifier( event.getInstanceToLoad(), event.getEntityId(), session );
} }
final Object entity = doLoad( event, persister, keyToLoad, options ); final Object entity = doLoad( event, persister, keyToLoad, options );
boolean isOptionalInstance = event.getInstanceToLoad() != null; boolean isOptionalInstance = event.getInstanceToLoad() != null;
if ( entity == null if ( entity == null
&& ( !options.isAllowNulls() || isOptionalInstance ) ) { && ( !options.isAllowNulls() || isOptionalInstance ) ) {
session.getFactory().getEntityNotFoundDelegate() event.getFactory().getEntityNotFoundDelegate()
.handleEntityNotFound( event.getEntityClassName(), event.getEntityId() ); .handleEntityNotFound( event.getEntityClassName(), event.getEntityId() );
} }
else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) { else if ( isOptionalInstance && entity != event.getInstanceToLoad() ) {
@ -397,7 +395,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
else { else {
if ( options != LoadEventListener.INTERNAL_LOAD_NULLABLE ) { if ( options != LoadEventListener.INTERNAL_LOAD_NULLABLE ) {
// throw an appropriate exception // throw an appropriate exception
event.getSession().getFactory().getEntityNotFoundDelegate() event.getFactory().getEntityNotFoundDelegate()
.handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() ); .handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() );
} }
// Otherwise, if it's INTERNAL_LOAD_NULLABLE, the proxy is // Otherwise, if it's INTERNAL_LOAD_NULLABLE, the proxy is
@ -448,8 +446,9 @@ public class DefaultLoadEventListener implements LoadEventListener {
private static Object createProxy(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) { private static Object createProxy(LoadEvent event, EntityPersister persister, EntityKey keyToLoad) {
// return new uninitialized proxy // return new uninitialized proxy
final Object proxy = persister.createProxy( event.getEntityId(), event.getSession() ); final EventSource session = event.getSession();
PersistenceContext persistenceContext = event.getSession().getPersistenceContextInternal(); final Object proxy = persister.createProxy( event.getEntityId(), session );
PersistenceContext persistenceContext = session.getPersistenceContextInternal();
persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad ); persistenceContext.getBatchFetchQueue().addBatchLoadableEntityKey( keyToLoad );
persistenceContext.addProxy( keyToLoad, proxy ); persistenceContext.addProxy( keyToLoad, proxy );
return proxy; return proxy;
@ -477,7 +476,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
ck = cache.generateCacheKey( ck = cache.generateCacheKey(
event.getEntityId(), event.getEntityId(),
persister, persister,
source.getFactory(), event.getFactory(),
source.getTenantIdentifier() source.getTenantIdentifier()
); );
lock = cache.lockItem( source, ck, null ); lock = cache.lockItem( source, ck, null );
@ -520,7 +519,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Attempting to resolve: {0}", "Attempting to resolve: {0}",
infoString( persister, event.getEntityId(), session.getFactory() ) infoString( persister, event.getEntityId(), event.getFactory() )
); );
} }
@ -575,7 +574,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Resolved object in second-level cache: {0}", "Resolved object in second-level cache: {0}",
infoString( persister, event.getEntityId(), event.getSession().getFactory() ) infoString( persister, event.getEntityId(), event.getFactory() )
); );
} }
return entity; return entity;
@ -584,7 +583,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Object not resolved in any cache: {0}", "Object not resolved in any cache: {0}",
infoString( persister, event.getEntityId(), event.getSession().getFactory() ) infoString( persister, event.getEntityId(), event.getFactory() )
); );
} }
return loadFromDatasource( event, persister ); return loadFromDatasource( event, persister );
@ -620,7 +619,7 @@ public class DefaultLoadEventListener implements LoadEventListener {
entity = lazyInitializer.getImplementation(); entity = lazyInitializer.getImplementation();
} }
final StatisticsImplementor statistics = event.getSession().getFactory().getStatistics(); final StatisticsImplementor statistics = event.getFactory().getStatistics();
if ( event.isAssociationFetch() && statistics.isStatisticsEnabled() ) { if ( event.isAssociationFetch() && statistics.isStatisticsEnabled() ) {
statistics.fetchEntity( event.getEntityClassName() ); statistics.fetchEntity( event.getEntityClassName() );
} }

View File

@ -216,16 +216,15 @@ public class DefaultMergeEventListener
entityIsPersistent( event, copiedAlready ); entityIsPersistent( event, copiedAlready );
break; break;
default: //DELETED default: //DELETED
if ( event.getSession().getPersistenceContext().getEntry( entity ) == null ) { if ( persistenceContext.getEntry( entity ) == null ) {
assert event.getSession().getPersistenceContext().containsDeletedUnloadedEntityKey( assert persistenceContext.containsDeletedUnloadedEntityKey(
event.getSession().generateEntityKey( source.generateEntityKey(
event.getSession() source.getEntityPersister( event.getEntityName(), entity )
.getEntityPersister( event.getEntityName(), entity )
.getIdentifier( entity, event.getSession() ), .getIdentifier( entity, event.getSession() ),
event.getSession().getEntityPersister( event.getEntityName(), entity ) source.getEntityPersister( event.getEntityName(), entity )
) )
); );
event.getSession().getActionQueue().unScheduleUnloadedDeletion( entity ); source.getActionQueue().unScheduleUnloadedDeletion( entity );
entityIsDetached(event, copiedId, originalId, copiedAlready); entityIsDetached(event, copiedId, originalId, copiedAlready);
break; break;
} }
@ -395,7 +394,7 @@ public class DefaultMergeEventListener
} }
final Object clonedIdentifier; final Object clonedIdentifier;
if ( copiedId == null ) { if ( copiedId == null ) {
clonedIdentifier = persister.getIdentifierType().deepCopy( originalId, source.getFactory() ); clonedIdentifier = persister.getIdentifierType().deepCopy( originalId, event.getFactory() );
} }
else { else {
clonedIdentifier = copiedId; clonedIdentifier = copiedId;

View File

@ -120,7 +120,7 @@ public class DefaultPersistEventListener
// entity state again. // entity state again.
// NOTE: entityEntry must be null to get here, so we cannot use any of its values // NOTE: entityEntry must be null to get here, so we cannot use any of its values
final EntityPersister persister = source.getFactory().getMappingMetamodel() final EntityPersister persister = event.getFactory().getMappingMetamodel()
.getEntityDescriptor( entityName ); .getEntityDescriptor( entityName );
if ( persister.getGenerator() instanceof ForeignGenerator ) { if ( persister.getGenerator() instanceof ForeignGenerator ) {
if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) { if ( LOG.isDebugEnabled() && persister.getIdentifier( entity, source ) != null ) {
@ -183,7 +183,7 @@ public class DefaultPersistEventListener
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracef( LOG.tracef(
"un-scheduling entity deletion [%s]", "un-scheduling entity deletion [%s]",
MessageHelper.infoString( persister, persister.getIdentifier( entity, source ), source.getFactory() ) MessageHelper.infoString( persister, persister.getIdentifier( entity, source ), event.getFactory() )
); );
} }
if ( createCache.add( entity ) ) { if ( createCache.add( entity ) ) {

View File

@ -134,7 +134,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Refreshing transient {0}", "Refreshing transient {0}",
infoString( persister, id, source.getFactory() ) infoString( persister, id, event.getFactory() )
); );
} }
if ( persistenceContext.getEntry( source.generateEntityKey( id, persister ) ) != null ) { if ( persistenceContext.getEntry( source.generateEntityKey( id, persister ) ) != null ) {
@ -145,7 +145,7 @@ public class DefaultRefreshEventListener implements RefreshEventListener {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Refreshing ", "Refreshing ",
infoString( entry.getPersister(), entry.getId(), source.getFactory() ) infoString( entry.getPersister(), entry.getId(), event.getFactory() )
); );
} }
if ( !entry.isExistsInDatabase() ) { if ( !entry.isExistsInDatabase() ) {

View File

@ -85,11 +85,8 @@ public class DefaultReplicateEventListener
if ( oldVersion != null ) { if ( oldVersion != null ) {
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Found existing row for {0}", MessageHelper.infoString( "Found existing row for {0}",
persister, MessageHelper.infoString( persister, id, event.getFactory() )
id,
source.getFactory()
)
); );
} }
@ -119,7 +116,7 @@ public class DefaultReplicateEventListener
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"No existing row, replicating new instance {0}", "No existing row, replicating new instance {0}",
MessageHelper.infoString( persister, id, source.getFactory() ) MessageHelper.infoString( persister, id, event.getFactory() )
); );
} }

View File

@ -14,7 +14,6 @@ import org.hibernate.event.spi.ResolveNaturalIdEventListener;
import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.concurrent.TimeUnit.MILLISECONDS;
@ -106,7 +105,7 @@ public class DefaultResolveNaturalIdEventListener
protected Object loadFromDatasource(ResolveNaturalIdEvent event) { protected Object loadFromDatasource(ResolveNaturalIdEvent event) {
final EventSource session = event.getSession(); final EventSource session = event.getSession();
final EntityPersister entityPersister = event.getEntityPersister(); final EntityPersister entityPersister = event.getEntityPersister();
final StatisticsImplementor statistics = session.getFactory().getStatistics(); final StatisticsImplementor statistics = event.getFactory().getStatistics();
final boolean statisticsEnabled = statistics.isStatisticsEnabled(); final boolean statisticsEnabled = statistics.isStatisticsEnabled();
final long startTime = statisticsEnabled ? System.nanoTime() : 0; final long startTime = statisticsEnabled ? System.nanoTime() : 0;

View File

@ -120,7 +120,7 @@ public class DefaultSaveOrUpdateEventListener
throw new AssertionFailure( "entity was deleted" ); throw new AssertionFailure( "entity was deleted" );
} }
final SessionFactoryImplementor factory = event.getSession().getFactory(); final SessionFactoryImplementor factory = event.getFactory();
final Object requestedId = event.getRequestedId(); final Object requestedId = event.getRequestedId();
final Object savedId; final Object savedId;
@ -250,7 +250,7 @@ public class DefaultSaveOrUpdateEventListener
} }
LOG.tracev( LOG.tracev(
"Updating {0}", "Updating {0}",
MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() ) MessageHelper.infoString( persister, event.getRequestedId(), event.getFactory() )
); );
} }
@ -293,7 +293,7 @@ public class DefaultSaveOrUpdateEventListener
if ( LOG.isTraceEnabled() ) { if ( LOG.isTraceEnabled() ) {
LOG.tracev( LOG.tracev(
"Updating {0}", "Updating {0}",
MessageHelper.infoString( persister, event.getRequestedId(), source.getFactory() ) MessageHelper.infoString( persister, event.getRequestedId(), event.getFactory() )
); );
} }

View File

@ -6,7 +6,6 @@
*/ */
package org.hibernate.event.internal; package org.hibernate.event.internal;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostUpdateEvent; import org.hibernate.event.spi.PostUpdateEvent;
@ -33,9 +32,9 @@ public class PostUpdateEventListenerStandardImpl implements PostUpdateEventListe
} }
private void handlePostUpdate(Object entity, EventSource source) { private void handlePostUpdate(Object entity, EventSource source) {
EntityEntry entry = source.getPersistenceContextInternal().getEntry( entity );
// mimic the preUpdate filter // mimic the preUpdate filter
if ( Status.DELETED != entry.getStatus() ) { if ( source == null // it must be a StatelessSession
|| source.getPersistenceContextInternal().getEntry(entity).getStatus() != Status.DELETED ) {
callbackRegistry.postUpdate(entity); callbackRegistry.postUpdate(entity);
} }
} }

View File

@ -0,0 +1,46 @@
/*
* 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.event.internal;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PostUpsertEvent;
import org.hibernate.event.spi.PostUpsertEventListener;
import org.hibernate.jpa.event.spi.CallbackRegistry;
import org.hibernate.jpa.event.spi.CallbackRegistryConsumer;
import org.hibernate.persister.entity.EntityPersister;
/**
* This is just a stub, since we don't yet have a {@code @PostUpsert} callback
*
* @author Gavin King
*/
public class PostUpsertEventListenerStandardImpl implements PostUpsertEventListener, CallbackRegistryConsumer {
private CallbackRegistry callbackRegistry;
@Override
public void injectCallbackRegistry(CallbackRegistry callbackRegistry) {
this.callbackRegistry = callbackRegistry;
}
@Override
public void onPostUpsert(PostUpsertEvent event) {
handlePostUpsert( event.getEntity(), event.getSession() );
}
private void handlePostUpsert(Object entity, EventSource source) {
// // mimic the preUpdate filter
// if ( source == null // it must be a StatelessSession
// || source.getPersistenceContextInternal().getEntry(entity).getStatus() != Status.DELETED ) {
// callbackRegistry.postUpdate(entity);
// }
}
@Override
public boolean requiresPostCommitHandling(EntityPersister persister) {
return false; //callbackRegistry.hasRegisteredCallbacks( persister.getMappedClass(), CallbackType.POST_UPDATE );
}
}

View File

@ -38,6 +38,7 @@ import org.hibernate.event.internal.DefaultUpdateEventListener;
import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl; import org.hibernate.event.internal.PostDeleteEventListenerStandardImpl;
import org.hibernate.event.internal.PostInsertEventListenerStandardImpl; import org.hibernate.event.internal.PostInsertEventListenerStandardImpl;
import org.hibernate.event.internal.PostUpdateEventListenerStandardImpl; import org.hibernate.event.internal.PostUpdateEventListenerStandardImpl;
import org.hibernate.event.internal.PostUpsertEventListenerStandardImpl;
import org.hibernate.event.service.spi.DuplicationStrategy; import org.hibernate.event.service.spi.DuplicationStrategy;
import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistrationException; import org.hibernate.event.service.spi.EventListenerRegistrationException;
@ -68,6 +69,7 @@ import static org.hibernate.event.spi.EventType.POST_DELETE;
import static org.hibernate.event.spi.EventType.POST_INSERT; import static org.hibernate.event.spi.EventType.POST_INSERT;
import static org.hibernate.event.spi.EventType.POST_LOAD; import static org.hibernate.event.spi.EventType.POST_LOAD;
import static org.hibernate.event.spi.EventType.POST_UPDATE; import static org.hibernate.event.spi.EventType.POST_UPDATE;
import static org.hibernate.event.spi.EventType.POST_UPSERT;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_RECREATE; import static org.hibernate.event.spi.EventType.PRE_COLLECTION_RECREATE;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_REMOVE; import static org.hibernate.event.spi.EventType.PRE_COLLECTION_REMOVE;
import static org.hibernate.event.spi.EventType.PRE_COLLECTION_UPDATE; import static org.hibernate.event.spi.EventType.PRE_COLLECTION_UPDATE;
@ -75,6 +77,7 @@ import static org.hibernate.event.spi.EventType.PRE_DELETE;
import static org.hibernate.event.spi.EventType.PRE_INSERT; import static org.hibernate.event.spi.EventType.PRE_INSERT;
import static org.hibernate.event.spi.EventType.PRE_LOAD; import static org.hibernate.event.spi.EventType.PRE_LOAD;
import static org.hibernate.event.spi.EventType.PRE_UPDATE; import static org.hibernate.event.spi.EventType.PRE_UPDATE;
import static org.hibernate.event.spi.EventType.PRE_UPSERT;
import static org.hibernate.event.spi.EventType.REFRESH; import static org.hibernate.event.spi.EventType.REFRESH;
import static org.hibernate.event.spi.EventType.REPLICATE; import static org.hibernate.event.spi.EventType.REPLICATE;
import static org.hibernate.event.spi.EventType.RESOLVE_NATURAL_ID; import static org.hibernate.event.spi.EventType.RESOLVE_NATURAL_ID;
@ -97,14 +100,14 @@ public class EventListenerRegistryImpl implements EventListenerRegistry {
this.eventListeners = eventListeners; this.eventListeners = eventListeners;
} }
@SuppressWarnings("unchecked")
public <T> EventListenerGroup<T> getEventListenerGroup(EventType<T> eventType) { public <T> EventListenerGroup<T> getEventListenerGroup(EventType<T> eventType) {
if ( eventListeners.length < eventType.ordinal() + 1 ) { if ( eventListeners.length < eventType.ordinal() + 1 ) {
// eventTpe is a custom EventType that has not been registered. // eventType is a custom EventType that has not been registered.
// registeredEventListeners array was not allocated enough space to // registeredEventListeners array was not allocated enough space to
// accommodate it. // accommodate it.
throw new HibernateException( "Unable to find listeners for type [" + eventType.eventName() + "]" ); throw new HibernateException( "Unable to find listeners for type [" + eventType.eventName() + "]" );
} }
@SuppressWarnings("unchecked")
final EventListenerGroup<T> listeners = eventListeners[ eventType.ordinal() ]; final EventListenerGroup<T> listeners = eventListeners[ eventType.ordinal() ];
if ( listeners == null ) { if ( listeners == null ) {
throw new HibernateException( "Unable to find listeners for type [" + eventType.eventName() + "]" ); throw new HibernateException( "Unable to find listeners for type [" + eventType.eventName() + "]" );
@ -278,6 +281,9 @@ public class EventListenerRegistryImpl implements EventListenerRegistry {
// pre-update listeners // pre-update listeners
prepareListeners( PRE_UPDATE ); prepareListeners( PRE_UPDATE );
// pre-update listeners
prepareListeners( PRE_UPSERT );
// post-collection-recreate listeners // post-collection-recreate listeners
prepareListeners( POST_COLLECTION_RECREATE ); prepareListeners( POST_COLLECTION_RECREATE );
@ -308,6 +314,9 @@ public class EventListenerRegistryImpl implements EventListenerRegistry {
// post-update listeners // post-update listeners
prepareListeners( POST_UPDATE, new PostUpdateEventListenerStandardImpl() ); prepareListeners( POST_UPDATE, new PostUpdateEventListenerStandardImpl() );
// post-upsert listeners
prepareListeners( POST_UPSERT, new PostUpsertEventListenerStandardImpl() );
// update listeners // update listeners
prepareListeners( UPDATE, new DefaultUpdateEventListener() ); prepareListeners( UPDATE, new DefaultUpdateEventListener() );

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import java.io.Serializable; import java.io.Serializable;
/** /**
@ -36,4 +38,7 @@ public abstract class AbstractEvent implements Serializable {
return session; return session;
} }
public SessionFactoryImplementor getFactory() {
return session.getFactory();
}
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
@ -64,5 +65,15 @@ public abstract class AbstractPreDatabaseOperationEvent extends AbstractEvent {
public EntityPersister getPersister() { public EntityPersister getPersister() {
return persister; return persister;
} }
/**
* The factory which owns the persister for the entity.
*
* @return The factory
*/
@Override
public SessionFactoryImplementor getFactory() {
return persister.getFactory();
}
} }

View File

@ -61,11 +61,13 @@ public final class EventType<T> {
public static final EventType<PreDeleteEventListener> PRE_DELETE = create( "pre-delete", PreDeleteEventListener.class ); public static final EventType<PreDeleteEventListener> PRE_DELETE = create( "pre-delete", PreDeleteEventListener.class );
public static final EventType<PreUpdateEventListener> PRE_UPDATE = create( "pre-update", PreUpdateEventListener.class ); public static final EventType<PreUpdateEventListener> PRE_UPDATE = create( "pre-update", PreUpdateEventListener.class );
public static final EventType<PreInsertEventListener> PRE_INSERT = create( "pre-insert", PreInsertEventListener.class ); public static final EventType<PreInsertEventListener> PRE_INSERT = create( "pre-insert", PreInsertEventListener.class );
public static final EventType<PreUpsertEventListener> PRE_UPSERT = create( "pre-upsert", PreUpsertEventListener.class );
public static final EventType<PostLoadEventListener> POST_LOAD = create( "post-load", PostLoadEventListener.class ); public static final EventType<PostLoadEventListener> POST_LOAD = create( "post-load", PostLoadEventListener.class );
public static final EventType<PostDeleteEventListener> POST_DELETE = create( "post-delete", PostDeleteEventListener.class ); public static final EventType<PostDeleteEventListener> POST_DELETE = create( "post-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_UPDATE = create( "post-update", PostUpdateEventListener.class ); public static final EventType<PostUpdateEventListener> POST_UPDATE = create( "post-update", PostUpdateEventListener.class );
public static final EventType<PostInsertEventListener> POST_INSERT = create( "post-insert", PostInsertEventListener.class ); public static final EventType<PostInsertEventListener> POST_INSERT = create( "post-insert", PostInsertEventListener.class );
public static final EventType<PostUpsertEventListener> POST_UPSERT = create( "post-upsert", PostUpsertEventListener.class );
public static final EventType<PostDeleteEventListener> POST_COMMIT_DELETE = create( "post-commit-delete", PostDeleteEventListener.class ); public static final EventType<PostDeleteEventListener> POST_COMMIT_DELETE = create( "post-commit-delete", PostDeleteEventListener.class );
public static final EventType<PostUpdateEventListener> POST_COMMIT_UPDATE = create( "post-commit-update", PostUpdateEventListener.class ); public static final EventType<PostUpdateEventListener> POST_COMMIT_UPDATE = create( "post-commit-update", PostUpdateEventListener.class );

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
@ -40,6 +41,11 @@ public class PostDeleteEvent extends AbstractEvent {
return persister; return persister;
} }
@Override
public SessionFactoryImplementor getFactory() {
return persister.getFactory();
}
public Object getEntity() { public Object getEntity() {
return entity; return entity;
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
@ -43,6 +44,12 @@ public class PostInsertEvent extends AbstractEvent {
public EntityPersister getPersister() { public EntityPersister getPersister() {
return persister; return persister;
} }
@Override
public SessionFactoryImplementor getFactory() {
return persister.getFactory();
}
public Object[] getState() { public Object[] getState() {
return state; return state;
} }

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.event.spi; package org.hibernate.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
/** /**
@ -56,6 +57,11 @@ public class PostUpdateEvent extends AbstractEvent {
return persister; return persister;
} }
@Override
public SessionFactoryImplementor getFactory() {
return persister.getFactory();
}
public Object[] getState() { public Object[] getState() {
return state; return state;
} }

View File

@ -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.event.spi;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.persister.entity.EntityPersister;
/**
* Occurs after the datastore is updated
*
* @author Gavin King
*/
public class PostUpsertEvent extends AbstractEvent {
private Object entity;
private EntityPersister persister;
private Object[] state;
private Object id;
//list of dirty properties as computed by Hibernate during a FlushEntityEvent
private final int[] dirtyProperties;
public PostUpsertEvent(
Object entity,
Object id,
Object[] state,
int[] dirtyProperties,
EntityPersister persister,
EventSource source
) {
super(source);
this.entity = entity;
this.id = id;
this.state = state;
this.dirtyProperties = dirtyProperties;
this.persister = persister;
}
public Object getEntity() {
return entity;
}
public Object getId() {
return id;
}
public EntityPersister getPersister() {
return persister;
}
@Override
public SessionFactoryImplementor getFactory() {
return persister.getFactory();
}
public Object[] getState() {
return state;
}
public int[] getDirtyProperties() {
return dirtyProperties;
}
}

View File

@ -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.event.spi;
/**
* Called after updating the datastore
*
* @author Gavin King
*/
public interface PostUpsertEventListener extends PostActionEventListener {
void onPostUpsert(PostUpsertEvent event);
}

View File

@ -22,7 +22,7 @@ public class PreDeleteEvent extends AbstractPreDatabaseOperationEvent {
/** /**
* Constructs an event containing the pertinent information. * Constructs an event containing the pertinent information.
* @param entity The entity to be deleted. * @param entity The entity to be deleted.
* @param id The id to use in the deletion. * @param id The id to use in the deletion.
* @param deletedState The entity's state at deletion time. * @param deletedState The entity's state at deletion time.
* @param persister The entity's persister. * @param persister The entity's persister.

View File

@ -16,11 +16,11 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class PreInsertEvent extends AbstractPreDatabaseOperationEvent { public class PreInsertEvent extends AbstractPreDatabaseOperationEvent {
private Object[] state; private final Object[] state;
/** /**
* Constructs an event containing the pertinent information. * Constructs an event containing the pertinent information.
* @param entity The entity to be inserted. * @param entity The entity to be inserted.
* @param id The id to use in the insertion. * @param id The id to use in the insertion.
* @param state The state to be inserted. * @param state The state to be inserted.
* @param persister The entity's persister. * @param persister The entity's persister.

View File

@ -16,16 +16,16 @@ import org.hibernate.persister.entity.EntityPersister;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class PreUpdateEvent extends AbstractPreDatabaseOperationEvent { public class PreUpdateEvent extends AbstractPreDatabaseOperationEvent {
private Object[] state; private final Object[] state;
private Object[] oldState; private final Object[] oldState;
/** /**
* Constructs an event containing the pertinent information. * Constructs an event containing the pertinent information.
* @param entity The entity to be updated. * @param entity The entity to be updated.
* @param id The id of the entity to use for updating. * @param id The id of the entity to use for updating.
* @param state The state to be updated. * @param state The state to be updated.
* @param oldState The state of the entity at the time it was loaded from * @param oldState The state of the entity at the time it was loaded from
* the database. * the database.
* @param persister The entity's persister. * @param persister The entity's persister.
* @param source The session from which the event originated. * @param source The session from which the event originated.
*/ */

View File

@ -0,0 +1,46 @@
/*
* 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.event.spi;
import org.hibernate.persister.entity.EntityPersister;
/**
* Represents a pre-upsert event, which occurs just prior to
* performing the upsert of an entity in the database.
*
* @author Gavin King
*/
public class PreUpsertEvent extends AbstractPreDatabaseOperationEvent {
private final Object[] state;
/**
* Constructs an event containing the pertinent information.
* @param entity The entity to be updated.
* @param id The id of the entity to use for updating.
* @param state The state to be updated.
* @param persister The entity's persister.
* @param source The session from which the event originated.
*/
public PreUpsertEvent(
Object entity,
Object id,
Object[] state,
EntityPersister persister,
EventSource source) {
super( source, entity, id, persister );
this.state = state;
}
/**
* Retrieves the state to be used in the upsert.
*
* @return The current state.
*/
public Object[] getState() {
return state;
}
}

View File

@ -0,0 +1,19 @@
/*
* 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.event.spi;
/**
* Called before updating the datastore
*
* @author Gavin King
*/
public interface PreUpsertEventListener {
/**
* Return true if the operation should be vetoed
*/
boolean onPreUpsert(PreUpsertEvent event);
}

View File

@ -26,7 +26,6 @@ import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.internal.EmptyEventManager; import org.hibernate.event.internal.EmptyEventManager;
import org.hibernate.event.spi.EventManager;
import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.AutoFlushEventListener; import org.hibernate.event.spi.AutoFlushEventListener;
@ -34,6 +33,7 @@ import org.hibernate.event.spi.ClearEventListener;
import org.hibernate.event.spi.DeleteEventListener; import org.hibernate.event.spi.DeleteEventListener;
import org.hibernate.event.spi.DirtyCheckEventListener; import org.hibernate.event.spi.DirtyCheckEventListener;
import org.hibernate.event.spi.EntityCopyObserverFactory; import org.hibernate.event.spi.EntityCopyObserverFactory;
import org.hibernate.event.spi.EventManager;
import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.EvictEventListener; import org.hibernate.event.spi.EvictEventListener;
import org.hibernate.event.spi.FlushEntityEventListener; import org.hibernate.event.spi.FlushEntityEventListener;
@ -51,6 +51,7 @@ import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener; import org.hibernate.event.spi.PostLoadEventListener;
import org.hibernate.event.spi.PostUpdateEventListener; import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.event.spi.PostUpsertEventListener;
import org.hibernate.event.spi.PreCollectionRecreateEventListener; import org.hibernate.event.spi.PreCollectionRecreateEventListener;
import org.hibernate.event.spi.PreCollectionRemoveEventListener; import org.hibernate.event.spi.PreCollectionRemoveEventListener;
import org.hibernate.event.spi.PreCollectionUpdateEventListener; import org.hibernate.event.spi.PreCollectionUpdateEventListener;
@ -58,6 +59,7 @@ import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.event.spi.PreInsertEventListener; import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.PreLoadEventListener; import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.event.spi.PreUpdateEventListener; import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.event.spi.PreUpsertEventListener;
import org.hibernate.event.spi.RefreshEventListener; import org.hibernate.event.spi.RefreshEventListener;
import org.hibernate.event.spi.ReplicateEventListener; import org.hibernate.event.spi.ReplicateEventListener;
import org.hibernate.event.spi.ResolveNaturalIdEventListener; import org.hibernate.event.spi.ResolveNaturalIdEventListener;
@ -140,6 +142,7 @@ public final class FastSessionServices {
public final EventListenerGroup<PostLoadEventListener> eventListenerGroup_POST_LOAD; //Frequently used by 2LC initialization: public final EventListenerGroup<PostLoadEventListener> eventListenerGroup_POST_LOAD; //Frequently used by 2LC initialization:
public final EventListenerGroup<PostUpdateEventListener> eventListenerGroup_POST_COMMIT_UPDATE; public final EventListenerGroup<PostUpdateEventListener> eventListenerGroup_POST_COMMIT_UPDATE;
public final EventListenerGroup<PostUpdateEventListener> eventListenerGroup_POST_UPDATE; public final EventListenerGroup<PostUpdateEventListener> eventListenerGroup_POST_UPDATE;
public final EventListenerGroup<PostUpsertEventListener> eventListenerGroup_POST_UPSERT;
public final EventListenerGroup<PreCollectionRecreateEventListener> eventListenerGroup_PRE_COLLECTION_RECREATE; public final EventListenerGroup<PreCollectionRecreateEventListener> eventListenerGroup_PRE_COLLECTION_RECREATE;
public final EventListenerGroup<PreCollectionRemoveEventListener> eventListenerGroup_PRE_COLLECTION_REMOVE; public final EventListenerGroup<PreCollectionRemoveEventListener> eventListenerGroup_PRE_COLLECTION_REMOVE;
public final EventListenerGroup<PreCollectionUpdateEventListener> eventListenerGroup_PRE_COLLECTION_UPDATE; public final EventListenerGroup<PreCollectionUpdateEventListener> eventListenerGroup_PRE_COLLECTION_UPDATE;
@ -147,6 +150,7 @@ public final class FastSessionServices {
public final EventListenerGroup<PreInsertEventListener> eventListenerGroup_PRE_INSERT; public final EventListenerGroup<PreInsertEventListener> eventListenerGroup_PRE_INSERT;
public final EventListenerGroup<PreLoadEventListener> eventListenerGroup_PRE_LOAD; public final EventListenerGroup<PreLoadEventListener> eventListenerGroup_PRE_LOAD;
public final EventListenerGroup<PreUpdateEventListener> eventListenerGroup_PRE_UPDATE; public final EventListenerGroup<PreUpdateEventListener> eventListenerGroup_PRE_UPDATE;
public final EventListenerGroup<PreUpsertEventListener> eventListenerGroup_PRE_UPSERT;
public final EventListenerGroup<RefreshEventListener> eventListenerGroup_REFRESH; public final EventListenerGroup<RefreshEventListener> eventListenerGroup_REFRESH;
public final EventListenerGroup<ReplicateEventListener> eventListenerGroup_REPLICATE; public final EventListenerGroup<ReplicateEventListener> eventListenerGroup_REPLICATE;
public final EventListenerGroup<ResolveNaturalIdEventListener> eventListenerGroup_RESOLVE_NATURAL_ID; public final EventListenerGroup<ResolveNaturalIdEventListener> eventListenerGroup_RESOLVE_NATURAL_ID;
@ -220,6 +224,7 @@ public final class FastSessionServices {
this.eventListenerGroup_POST_INSERT = listeners( eventListenerRegistry, EventType.POST_INSERT ); this.eventListenerGroup_POST_INSERT = listeners( eventListenerRegistry, EventType.POST_INSERT );
this.eventListenerGroup_POST_LOAD = listeners( eventListenerRegistry, EventType.POST_LOAD ); this.eventListenerGroup_POST_LOAD = listeners( eventListenerRegistry, EventType.POST_LOAD );
this.eventListenerGroup_POST_UPDATE = listeners( eventListenerRegistry, EventType.POST_UPDATE ); this.eventListenerGroup_POST_UPDATE = listeners( eventListenerRegistry, EventType.POST_UPDATE );
this.eventListenerGroup_POST_UPSERT = listeners( eventListenerRegistry, EventType.POST_UPSERT );
this.eventListenerGroup_PRE_COLLECTION_RECREATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_RECREATE ); this.eventListenerGroup_PRE_COLLECTION_RECREATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_RECREATE );
this.eventListenerGroup_PRE_COLLECTION_REMOVE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_REMOVE ); this.eventListenerGroup_PRE_COLLECTION_REMOVE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_REMOVE );
this.eventListenerGroup_PRE_COLLECTION_UPDATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_UPDATE ); this.eventListenerGroup_PRE_COLLECTION_UPDATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_UPDATE );
@ -227,6 +232,7 @@ public final class FastSessionServices {
this.eventListenerGroup_PRE_INSERT = listeners( eventListenerRegistry, EventType.PRE_INSERT ); this.eventListenerGroup_PRE_INSERT = listeners( eventListenerRegistry, EventType.PRE_INSERT );
this.eventListenerGroup_PRE_LOAD = listeners( eventListenerRegistry, EventType.PRE_LOAD ); this.eventListenerGroup_PRE_LOAD = listeners( eventListenerRegistry, EventType.PRE_LOAD );
this.eventListenerGroup_PRE_UPDATE = listeners( eventListenerRegistry, EventType.PRE_UPDATE ); this.eventListenerGroup_PRE_UPDATE = listeners( eventListenerRegistry, EventType.PRE_UPDATE );
this.eventListenerGroup_PRE_UPSERT = listeners( eventListenerRegistry, EventType.PRE_UPSERT );
this.eventListenerGroup_REFRESH = listeners( eventListenerRegistry, EventType.REFRESH ); this.eventListenerGroup_REFRESH = listeners( eventListenerRegistry, EventType.REFRESH );
this.eventListenerGroup_REPLICATE = listeners( eventListenerRegistry, EventType.REPLICATE ); this.eventListenerGroup_REPLICATE = listeners( eventListenerRegistry, EventType.REPLICATE );
this.eventListenerGroup_RESOLVE_NATURAL_ID = listeners( eventListenerRegistry, EventType.RESOLVE_NATURAL_ID ); this.eventListenerGroup_RESOLVE_NATURAL_ID = listeners( eventListenerRegistry, EventType.RESOLVE_NATURAL_ID );

View File

@ -32,6 +32,22 @@ import org.hibernate.engine.spi.PersistentAttributeInterceptable;
import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.PersistentAttributeInterceptor;
import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.spi.PostDeleteEvent;
import org.hibernate.event.spi.PostDeleteEventListener;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.event.spi.PostUpsertEvent;
import org.hibernate.event.spi.PostUpsertEventListener;
import org.hibernate.event.spi.PreDeleteEvent;
import org.hibernate.event.spi.PreDeleteEventListener;
import org.hibernate.event.spi.PreInsertEvent;
import org.hibernate.event.spi.PreInsertEventListener;
import org.hibernate.event.spi.PreUpdateEvent;
import org.hibernate.event.spi.PreUpdateEventListener;
import org.hibernate.event.spi.PreUpsertEvent;
import org.hibernate.event.spi.PreUpsertEventListener;
import org.hibernate.generator.BeforeExecutionGenerator; import org.hibernate.generator.BeforeExecutionGenerator;
import org.hibernate.generator.Generator; import org.hibernate.generator.Generator;
import org.hibernate.generator.values.GeneratedValues; import org.hibernate.generator.values.GeneratedValues;
@ -114,15 +130,22 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
persister.setValues( entity, state ); persister.setValues( entity, state );
} }
} }
if ( firePreInsert(entity, id, state, persister) ) {
return id;
}
persister.getInsertCoordinator().insert( entity, id, state, this ); persister.getInsertCoordinator().insert( entity, id, state, this );
} }
else { else {
if ( firePreInsert(entity, null, state, persister) ) {
return null;
}
final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this ); final GeneratedValues generatedValues = persister.getInsertCoordinator().insert( entity, state, this );
id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() ); id = castNonNull( generatedValues ).getGeneratedValue( persister.getIdentifierMapping() );
} }
persister.setIdentifier( entity, id, this ); persister.setIdentifier( entity, id, this );
forEachOwnedCollection( entity, id, persister, forEachOwnedCollection( entity, id, persister,
(descriptor, collection) -> descriptor.recreate( collection, id, this) ); (descriptor, collection) -> descriptor.recreate( collection, id, this) );
firePostInsert(entity, id, state, persister);
return id; return id;
} }
@ -140,9 +163,12 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
final EntityPersister persister = getEntityPersister( entityName, entity ); final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = persister.getIdentifier( entity, this ); final Object id = persister.getIdentifier( entity, this );
final Object version = persister.getVersion( entity ); final Object version = persister.getVersion( entity );
forEachOwnedCollection( entity, id, persister, if ( !firePreDelete(entity, id, persister) ) {
(descriptor, collection) -> descriptor.remove(id, this) ); forEachOwnedCollection( entity, id, persister,
persister.getDeleteCoordinator().delete( entity, id, version, this ); (descriptor, collection) -> descriptor.remove(id, this) );
persister.getDeleteCoordinator().delete( entity, id, version, this );
firePostDelete(entity, id, persister);
}
} }
@ -176,12 +202,15 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
else { else {
oldVersion = null; oldVersion = null;
} }
persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this ); if ( !firePreUpdate(entity, id, state, persister) ) {
// TODO: can we do better here? persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
forEachOwnedCollection( entity, id, persister, // TODO: can we do better here?
(descriptor, collection) -> descriptor.remove(id, this) ); forEachOwnedCollection( entity, id, persister,
forEachOwnedCollection( entity, id, persister, (descriptor, collection) -> descriptor.remove(id, this) );
(descriptor, collection) -> descriptor.recreate( collection, id, this) ); forEachOwnedCollection( entity, id, persister,
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
firePostUpdate(entity, id, state, persister);
}
} }
@Override @Override
@ -190,13 +219,17 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
final EntityPersister persister = getEntityPersister( entityName, entity ); final EntityPersister persister = getEntityPersister( entityName, entity );
final Object id = idToUpsert( entity, persister ); final Object id = idToUpsert( entity, persister );
final Object[] state = persister.getValues( entity ); final Object[] state = persister.getValues( entity );
final Object oldVersion = versionToUpsert( entity, persister, state ); if ( !firePreUpsert(entity, id, state, persister) ) {
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this ); final Object oldVersion = versionToUpsert( entity, persister, state );
// TODO: can we do better here? persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
forEachOwnedCollection( entity, id, persister, // TODO: need PreUpsert and PostUpsert events!
(descriptor, collection) -> descriptor.remove(id, this) ); // TODO: can we do better here?
forEachOwnedCollection( entity, id, persister, forEachOwnedCollection( entity, id, persister,
(descriptor, collection) -> descriptor.recreate( collection, id, this) ); (descriptor, collection) -> descriptor.remove(id, this) );
forEachOwnedCollection( entity, id, persister,
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
firePostUpsert(entity, id, state, persister);
}
} }
private Object versionToUpsert(Object entity, EntityPersister persister, Object[] state) { private Object versionToUpsert(Object entity, EntityPersister persister, Object[] state) {
@ -239,6 +272,100 @@ public class StatelessSessionImpl extends AbstractSharedSessionContract implemen
return id; return id;
} }
// event processing ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private boolean firePreInsert(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( fastSessionServices.eventListenerGroup_PRE_INSERT.isEmpty() ) {
return false;
}
else {
boolean veto = false;
final PreInsertEvent event = new PreInsertEvent( entity, id, state, persister, null );
for ( PreInsertEventListener listener : fastSessionServices.eventListenerGroup_PRE_INSERT.listeners() ) {
veto |= listener.onPreInsert( event );
}
return veto;
}
}
private boolean firePreUpdate(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( fastSessionServices.eventListenerGroup_PRE_UPDATE.isEmpty() ) {
return false;
}
else {
boolean veto = false;
final PreUpdateEvent event = new PreUpdateEvent( entity, id, state, null, persister, null );
for ( PreUpdateEventListener listener : fastSessionServices.eventListenerGroup_PRE_UPDATE.listeners() ) {
veto |= listener.onPreUpdate( event );
}
return veto;
}
}
private boolean firePreUpsert(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( fastSessionServices.eventListenerGroup_PRE_UPSERT.isEmpty() ) {
return false;
}
else {
boolean veto = false;
final PreUpsertEvent event = new PreUpsertEvent( entity, id, state, persister, null );
for ( PreUpsertEventListener listener : fastSessionServices.eventListenerGroup_PRE_UPSERT.listeners() ) {
veto |= listener.onPreUpsert( event );
}
return veto;
}
}
private boolean firePreDelete(Object entity, Object id, EntityPersister persister) {
if ( fastSessionServices.eventListenerGroup_PRE_DELETE.isEmpty() ) {
return false;
}
else {
boolean veto = false;
final PreDeleteEvent event = new PreDeleteEvent( entity, id, null, persister, null );
for ( PreDeleteEventListener listener : fastSessionServices.eventListenerGroup_PRE_DELETE.listeners() ) {
veto |= listener.onPreDelete( event );
}
return veto;
}
}
private void firePostInsert(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( !fastSessionServices.eventListenerGroup_POST_INSERT.isEmpty() ) {
final PostInsertEvent event = new PostInsertEvent( entity, id, state, persister, null );
for ( PostInsertEventListener listener : fastSessionServices.eventListenerGroup_POST_INSERT.listeners() ) {
listener.onPostInsert( event );
}
}
}
private void firePostUpdate(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( !fastSessionServices.eventListenerGroup_POST_UPDATE.isEmpty() ) {
final PostUpdateEvent event = new PostUpdateEvent( entity, id, state, null, null, persister, null );
for ( PostUpdateEventListener listener : fastSessionServices.eventListenerGroup_POST_UPDATE.listeners() ) {
listener.onPostUpdate( event );
}
}
}
private void firePostUpsert(Object entity, Object id, Object[] state, EntityPersister persister) {
if ( !fastSessionServices.eventListenerGroup_POST_UPSERT.isEmpty() ) {
final PostUpsertEvent event = new PostUpsertEvent( entity, id, state, null, persister, null );
for ( PostUpsertEventListener listener : fastSessionServices.eventListenerGroup_POST_UPSERT.listeners() ) {
listener.onPostUpsert( event );
}
}
}
private void firePostDelete(Object entity, Object id, EntityPersister persister) {
if (!fastSessionServices.eventListenerGroup_POST_DELETE.isEmpty()) {
final PostDeleteEvent event = new PostDeleteEvent( entity, id, null, persister, null );
for ( PostDeleteEventListener listener : fastSessionServices.eventListenerGroup_POST_DELETE.listeners() ) {
listener.onPostDelete( event );
}
}
}
// collections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // collections ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
private void forEachOwnedCollection( private void forEachOwnedCollection(

View File

@ -169,8 +169,7 @@ public class CacheEntityLoaderHelper {
} }
} }
if ( options.isAllowNulls() ) { if ( options.isAllowNulls() ) {
final EntityPersister persister = event.getSession() final EntityPersister persister = event.getFactory()
.getFactory()
.getRuntimeMetamodels() .getRuntimeMetamodels()
.getMappingMetamodel() .getMappingMetamodel()
.getEntityDescriptor( keyToLoad.getEntityName() ); .getEntityDescriptor( keyToLoad.getEntityName() );
@ -215,7 +214,7 @@ public class CacheEntityLoaderHelper {
.setId( event.getEntityId() ) .setId( event.getEntityId() )
.setPersister( persister ); .setPersister( persister );
event.getSession().getSessionFactory() event.getFactory()
.getFastSessionServices() .getFastSessionServices()
.firePostLoadEvent( postLoadEvent ); .firePostLoadEvent( postLoadEvent );
} }

View File

@ -0,0 +1,107 @@
/*
* 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.orm.test.jpa.beanvalidation;
import jakarta.validation.ConstraintViolationException;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.hibernate.testing.orm.junit.Setting;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import java.math.BigDecimal;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.fail;
/**
* @author Emmanuel Bernard
*/
@SessionFactory
@DomainModel(annotatedClasses = CupHolder.class)
@ServiceRegistry(settings = @Setting(name = AvailableSettings.JAKARTA_VALIDATION_MODE, value = "auto"))
public class StatelessBeanValidationTest {
@AfterEach
public void tearDown(SessionFactoryScope scope){
scope.inTransaction(
session -> session.createQuery( "delete from CupHolder" ).executeUpdate()
);
}
@Test
public void testStatelessBeanValidationIntegrationOnInsert(SessionFactoryScope scope) {
scope.inStatelessTransaction(
entityManager -> {
CupHolder ch = new CupHolder();
ch.setRadius( new BigDecimal( "12" ) );
ch.setTitle( "foo" );
try {
entityManager.insert(ch);
fail( "invalid object should not be persisted" );
}
catch (ConstraintViolationException e) {
assertEquals( 1, e.getConstraintViolations().size() );
}
assertFalse(
entityManager.getTransaction().getRollbackOnly(),
"Stateless session errors don't need to mark the transaction for rollback"
);
}
);
}
@Test
public void testStatelessBeanValidationIntegrationOnUpdate(SessionFactoryScope scope) {
scope.inStatelessTransaction(
entityManager -> {
CupHolder ch = new CupHolder();
ch.setId(123);
ch.setRadius( new BigDecimal( "12" ) );
ch.setTitle( "foo" );
try {
entityManager.update(ch);
fail( "invalid object should not be persisted" );
}
catch (ConstraintViolationException e) {
assertEquals( 1, e.getConstraintViolations().size() );
}
assertFalse(
entityManager.getTransaction().getRollbackOnly(),
"Stateless session errors don't need to mark the transaction for rollback"
);
}
);
}
@Test
public void testStatelessBeanValidationIntegrationOnUpsert(SessionFactoryScope scope) {
scope.inStatelessTransaction(
entityManager -> {
CupHolder ch = new CupHolder();
ch.setId(123);
ch.setRadius( new BigDecimal( "12" ) );
ch.setTitle( "foo" );
try {
entityManager.upsert(ch);
fail( "invalid object should not be persisted" );
}
catch (ConstraintViolationException e) {
assertEquals( 1, e.getConstraintViolations().size() );
}
assertFalse(
entityManager.getTransaction().getRollbackOnly(),
"Stateless session errors don't need to mark the transaction for rollback"
);
}
);
}
}

View File

@ -0,0 +1,80 @@
package org.hibernate.orm.test.stateless;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.Id;
import jakarta.persistence.PostPersist;
import jakarta.persistence.PostRemove;
import jakarta.persistence.PostUpdate;
import jakarta.persistence.PrePersist;
import jakarta.persistence.PreRemove;
import jakarta.persistence.PreUpdate;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
@SessionFactory
@DomainModel(annotatedClasses = StatelessCallbacksTest.WithCallbacks.class)
public class StatelessCallbacksTest {
@Test void test(SessionFactoryScope scope) {
scope.inStatelessSession(s -> {
WithCallbacks instance = new WithCallbacks();
instance.name = "gavin";
s.insert(instance);
// because the semantics of @PrePersist and @PreRemove
// are inappropriate for a StatelessSession, the @Pre
// don't get called. However, the @Post events do make
// sense, since they correspond to database operations
assertFalse(instance.prePersist);
assertTrue(instance.postPersist);
s.update(instance);
assertFalse(instance.preUpdate);
assertTrue(instance.postUpdate);
s.delete(instance);
assertFalse(instance.preRemove);
assertTrue(instance.postRemove);
});
}
@Entity
static class WithCallbacks {
boolean prePersist = false;
boolean preUpdate = false;
boolean preRemove = false;
boolean postPersist = false;
boolean postUpdate = false;
boolean postRemove = false;
@GeneratedValue @Id
Long id;
String name;
@PrePersist
void prePersist() {
prePersist = true;
}
@PostPersist
void postPersist() {
postPersist = true;
}
@PreUpdate
void preUpdate() {
preUpdate = true;
}
@PostUpdate
void postUpdate() {
postUpdate = true;
}
@PreRemove
void preRemove() {
preRemove = true;
}
@PostRemove
void postRemove() {
postRemove = true;
}
}
}

View File

@ -12,7 +12,6 @@ import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.event.spi.AutoFlushEvent; import org.hibernate.event.spi.AutoFlushEvent;
import org.hibernate.event.spi.EventManager; import org.hibernate.event.spi.EventManager;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.HibernateMonitoringEvent; import org.hibernate.event.spi.HibernateMonitoringEvent;
import org.hibernate.internal.build.AllowNonPortable; import org.hibernate.internal.build.AllowNonPortable;
import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.persister.collection.CollectionPersister;
@ -453,8 +452,7 @@ public class JfrEventManager implements EventManager {
flushEvent.end(); flushEvent.end();
if ( flushEvent.shouldCommit() ) { if ( flushEvent.shouldCommit() ) {
flushEvent.executionTime = getExecutionTime( flushEvent.startedAt ); flushEvent.executionTime = getExecutionTime( flushEvent.startedAt );
EventSource session = event.getSession(); flushEvent.sessionIdentifier = getSessionIdentifier( event.getSession() );
flushEvent.sessionIdentifier = getSessionIdentifier( session );
flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed(); flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed();
flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed(); flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed();
flushEvent.isAutoFlush = autoFlush; flushEvent.isAutoFlush = autoFlush;
@ -485,8 +483,7 @@ public class JfrEventManager implements EventManager {
flushEvent.end(); flushEvent.end();
if ( flushEvent.shouldCommit() ) { if ( flushEvent.shouldCommit() ) {
flushEvent.executionTime = getExecutionTime( flushEvent.startedAt ); flushEvent.executionTime = getExecutionTime( flushEvent.startedAt );
EventSource session = event.getSession(); flushEvent.sessionIdentifier = getSessionIdentifier( event.getSession() );
flushEvent.sessionIdentifier = getSessionIdentifier( session );
flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed(); flushEvent.numberOfEntitiesProcessed = event.getNumberOfEntitiesProcessed();
flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed(); flushEvent.numberOfCollectionsProcessed = event.getNumberOfCollectionsProcessed();
flushEvent.isAutoFlush = true; flushEvent.isAutoFlush = true;

View File

@ -101,7 +101,7 @@ public class HibernateQueryMetrics implements MeterBinder {
@Override @Override
public void onPostLoad(PostLoadEvent event) { public void onPostLoad(PostLoadEvent event) {
registerQueryMetric( event.getSession().getFactory().getStatistics() ); registerQueryMetric( event.getFactory().getStatistics() );
} }
void registerQueryMetric(Statistics statistics) { void registerQueryMetric(Statistics statistics) {