HHH-17955 Bean Validation and @PostXxxx callbacks for StatelessSession
Signed-off-by: Gavin King <gavin@hibernate.org>
This commit is contained in:
parent
59603dffb3
commit
9a4d21d71d
|
@ -239,19 +239,20 @@ 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 veto;
|
return false;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
boolean veto = false;
|
||||||
final PreInsertEvent event = new PreInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() );
|
final PreInsertEvent event = new PreInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() );
|
||||||
for ( PreInsertEventListener listener : listenerGroup.listeners() ) {
|
for ( PreInsertEventListener listener : listenerGroup.listeners() ) {
|
||||||
veto |= listener.onPreInsert( event );
|
veto |= listener.onPreInsert( event );
|
||||||
}
|
}
|
||||||
return veto;
|
return veto;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
|
public void doAfterTransactionCompletion(boolean success, SharedSessionContractImplementor session) throws HibernateException {
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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" );
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
)
|
)
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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 ) ) {
|
||||||
|
|
|
@ -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() ) {
|
||||||
|
|
|
@ -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() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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() )
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 );
|
||||||
|
}
|
||||||
|
}
|
|
@ -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() );
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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 );
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -16,7 +16,7 @@ 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.
|
||||||
|
|
|
@ -16,8 +16,8 @@ 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.
|
||||||
|
@ -25,7 +25,7 @@ public class PreUpdateEvent extends AbstractPreDatabaseOperationEvent {
|
||||||
* @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.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
|
@ -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 );
|
||||||
|
|
|
@ -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 );
|
||||||
|
if ( !firePreDelete(entity, id, persister) ) {
|
||||||
forEachOwnedCollection( entity, id, persister,
|
forEachOwnedCollection( entity, id, persister,
|
||||||
(descriptor, collection) -> descriptor.remove(id, this) );
|
(descriptor, collection) -> descriptor.remove(id, this) );
|
||||||
persister.getDeleteCoordinator().delete( entity, id, version, 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;
|
||||||
}
|
}
|
||||||
|
if ( !firePreUpdate(entity, id, state, persister) ) {
|
||||||
persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
persister.getUpdateCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
||||||
// TODO: can we do better here?
|
// TODO: can we do better here?
|
||||||
forEachOwnedCollection( entity, id, persister,
|
forEachOwnedCollection( entity, id, persister,
|
||||||
(descriptor, collection) -> descriptor.remove(id, this) );
|
(descriptor, collection) -> descriptor.remove(id, this) );
|
||||||
forEachOwnedCollection( entity, id, persister,
|
forEachOwnedCollection( entity, id, persister,
|
||||||
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
|
(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 );
|
||||||
|
if ( !firePreUpsert(entity, id, state, persister) ) {
|
||||||
final Object oldVersion = versionToUpsert( entity, persister, state );
|
final Object oldVersion = versionToUpsert( entity, persister, state );
|
||||||
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
persister.getMergeCoordinator().update( entity, id, null, state, oldVersion, null, null, false, this );
|
||||||
|
// TODO: need PreUpsert and PostUpsert events!
|
||||||
// TODO: can we do better here?
|
// TODO: can we do better here?
|
||||||
forEachOwnedCollection( entity, id, persister,
|
forEachOwnedCollection( entity, id, persister,
|
||||||
(descriptor, collection) -> descriptor.remove(id, this) );
|
(descriptor, collection) -> descriptor.remove(id, this) );
|
||||||
forEachOwnedCollection( entity, id, persister,
|
forEachOwnedCollection( entity, id, persister,
|
||||||
(descriptor, collection) -> descriptor.recreate( collection, id, this) );
|
(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(
|
||||||
|
|
|
@ -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 );
|
||||||
}
|
}
|
||||||
|
|
|
@ -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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue