This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch 8.0.x-hibernate7 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 2ee2b852dc8fb669507e21c5ecb47ae2a3751797 Author: Walter Duque de Estrada <[email protected]> AuthorDate: Fri Feb 27 15:23:29 2026 -0600 Hibernate 7.2 --- gradle.properties | 2 +- .../orm/hibernate/GrailsHibernateTemplate.java | 11 +- .../domainbinding/binder/SimpleValueBinder.java | 9 +- .../domainbinding/util/BasicValueIdCreator.java | 10 +- .../hibernate/support/ClosureEventListener.java | 364 +++++++-------------- .../HibernateDialectDetectorFactoryBean.java | 5 + .../util/GeneratorCreationContextWrapper.java | 93 ++++++ .../domainbinding/BasicValueIdCreatorSpec.groovy | 10 +- .../GrailsSequenceGeneratorEnumSpec.groovy | 5 +- 9 files changed, 251 insertions(+), 258 deletions(-) diff --git a/gradle.properties b/gradle.properties index 31f8d9a58a..e87a20b74e 100644 --- a/gradle.properties +++ b/gradle.properties @@ -36,7 +36,7 @@ gparsVersion=1.2.1 # and grails-forge/grails-forge-core/src/main/java/org/grails/forge/feature/build/gradle/templates/gradleWrapperProperties.rocker.raw gradleToolingApiVersion=8.14.4 hibernate5Version=5.6.15.Final -hibernate7Version=7.1.11.Final +hibernate7Version=7.2.5.Final #hibernate7Version=7.2.4.Final javassistVersion=3.30.2-GA jnrPosixVersion=3.1.20 diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java index 54bf894f8b..474982d0d8 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/GrailsHibernateTemplate.java @@ -37,7 +37,6 @@ import java.util.List; import javax.sql.DataSource; import org.codehaus.groovy.runtime.DefaultGroovyMethods; import org.hibernate.*; -import org.hibernate.engine.jdbc.connections.internal.DatasourceConnectionProviderImpl; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; @@ -97,12 +96,12 @@ public class GrailsHibernateTemplate implements IHibernateTemplate { ((SessionFactoryImplementor) sessionFactory) .getServiceRegistry() .getService(ConnectionProvider.class); - if (connectionProvider instanceof DatasourceConnectionProviderImpl) { - this.dataSource = ((DatasourceConnectionProviderImpl) connectionProvider).getDataSource(); - if (dataSource instanceof TransactionAwareDataSourceProxy) { - this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource(); + this.dataSource = connectionProvider.unwrap(DataSource.class); + if (this.dataSource != null) { + if (this.dataSource instanceof TransactionAwareDataSourceProxy) { + this.dataSource = ((TransactionAwareDataSourceProxy) this.dataSource).getTargetDataSource(); } - jdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(dataSource); + jdbcExceptionTranslator = new SQLErrorCodeSQLExceptionTranslator(this.dataSource); } else { // must be in unit test mode, setup default translator SQLErrorCodeSQLExceptionTranslator sqlErrorCodeSQLExceptionTranslator = diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/SimpleValueBinder.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/SimpleValueBinder.java index 417d1299bf..161ac76f3d 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/SimpleValueBinder.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/SimpleValueBinder.java @@ -109,7 +109,14 @@ public class SimpleValueBinder { String generator = propertyConfig.getGenerator(); if (generator != null && simpleValue instanceof BasicValue basicValue) { basicValue.setCustomIdGeneratorCreator( - context -> createGenerator(property, context, generator)); + context -> + createGenerator( + property, + context.getValue() == null + ? new org.grails.orm.hibernate.cfg.domainbinding.util + .GeneratorCreationContextWrapper(context, basicValue) + : context, + generator)); } if (propertyConfig.isDerived() && !(property instanceof TenantId)) { diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/BasicValueIdCreator.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/BasicValueIdCreator.java index 0a2cb00ab5..04f824b7c5 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/BasicValueIdCreator.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/BasicValueIdCreator.java @@ -67,7 +67,15 @@ public class BasicValueIdCreator { // because table differs) String generatorName = Identity.determineGeneratorName(mappedId, useSequence); id.setCustomIdGeneratorCreator( - context -> createGenerator(mappedId, domainClass, context, generatorName)); + context -> + createGenerator( + mappedId, + domainClass, + context.getValue() == null + ? new org.grails.orm.hibernate.cfg.domainbinding.util + .GeneratorCreationContextWrapper(context, id) + : context, + generatorName)); return id; } diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/ClosureEventListener.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/ClosureEventListener.java index 22a472a499..b84e36be63 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/ClosureEventListener.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/ClosureEventListener.java @@ -18,13 +18,12 @@ */ package org.grails.orm.hibernate.support; -import groovy.lang.Closure; import groovy.lang.GroovySystem; import groovy.lang.MetaClass; -import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.concurrent.Callable; import org.grails.datastore.gorm.GormValidateable; import org.grails.datastore.gorm.support.BeforeValidateHelper.BeforeValidateEventTriggerCaller; import org.grails.datastore.gorm.support.EventTriggerCaller; @@ -40,9 +39,7 @@ import org.grails.orm.hibernate.AbstractHibernateGormValidationApi; import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Session; -import org.hibernate.action.internal.EntityUpdateAction; -import org.hibernate.engine.spi.ActionQueue; -import org.hibernate.engine.spi.ExecutableList; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.spi.*; import org.hibernate.jpa.event.spi.CallbackRegistry; import org.hibernate.jpa.event.spi.CallbackRegistryConsumer; @@ -51,31 +48,12 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.persister.entity.EntityPersister; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.util.ReflectionUtils; -import org.springframework.validation.Errors; -/** - * Invokes closure events on domain entities such as beforeInsert, beforeUpdate and beforeDelete. - * - * <p>Also deals with auto time stamping of domain classes that have properties named 'lastUpdated' - * and/or 'dateCreated'. - * - * @author Lari Hotari - * @author Graeme Rocher - * @since 1.3.5 - */ -@SuppressWarnings({ - "rawtypes", - "unchecked", - "serial", - "PMD.AvoidAccessibilityAlteration", - "PMD.DataflowAnomalyAnalysis", - "PMD.CompareObjectsWithEquals", - "PMD.CloseResource" -}) +@SuppressWarnings({"rawtypes", "unchecked", "serial"}) public class ClosureEventListener implements PreLoadEventListener, PostLoadEventListener, + PreInsertEventListener, // Added to fix "does not exist in superclass" error PostInsertEventListener, PostUpdateEventListener, PostDeleteEventListener, @@ -86,11 +64,8 @@ public class ClosureEventListener CallbackRegistryConsumer { private static final long serialVersionUID = 1; - - /** The log. */ protected static final Logger LOG = LoggerFactory.getLogger(ClosureEventListener.class); - private final EventTriggerCaller saveOrUpdateCaller; private final EventTriggerCaller beforeInsertCaller; private final EventTriggerCaller preLoadEventCaller; private final EventTriggerCaller postLoadEventListener; @@ -102,30 +77,22 @@ public class ClosureEventListener private final BeforeValidateEventTriggerCaller beforeValidateEventListener; private final PersistentEntity persistentEntity; private final MetaClass domainMetaClass; - private final boolean isMultiTenant; private final boolean failOnErrorEnabled; private final Map validateParams; - private Field actionQueueUpdatesField; - private Field entityUpdateActionStateField; - - /** Creates a new {@link ClosureEventListener} instance. */ public ClosureEventListener( PersistentEntity persistentEntity, boolean failOnError, List failOnErrorPackages) { this.persistentEntity = persistentEntity; Class domainClazz = persistentEntity.getJavaClass(); this.domainMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(domainClazz); - this.isMultiTenant = ClassUtils.isMultiTenant(domainClazz); - saveOrUpdateCaller = buildCaller(AbstractPersistenceEvent.ONLOAD_SAVE, domainClazz); + beforeInsertCaller = buildCaller(AbstractPersistenceEvent.BEFORE_INSERT_EVENT, domainClazz); - EventTriggerCaller preLoadEventCaller = + EventTriggerCaller preLoadCaller = buildCaller(AbstractPersistenceEvent.ONLOAD_EVENT, domainClazz); - if (preLoadEventCaller == null) { - this.preLoadEventCaller = - buildCaller(AbstractPersistenceEvent.BEFORE_LOAD_EVENT, domainClazz); - } else { - this.preLoadEventCaller = preLoadEventCaller; - } + this.preLoadEventCaller = + (preLoadCaller != null) + ? preLoadCaller + : buildCaller(AbstractPersistenceEvent.BEFORE_LOAD_EVENT, domainClazz); postLoadEventListener = buildCaller(AbstractPersistenceEvent.AFTER_LOAD_EVENT, domainClazz); postInsertEventListener = buildCaller(AbstractPersistenceEvent.AFTER_INSERT_EVENT, domainClazz); @@ -136,199 +103,136 @@ public class ClosureEventListener beforeValidateEventListener = new BeforeValidateEventTriggerCaller(domainClazz, domainMetaClass); - - if (failOnErrorPackages.size() > 0) { - failOnErrorEnabled = ClassUtils.isClassBelowPackage(domainClazz, failOnErrorPackages); - } else { - failOnErrorEnabled = failOnError; - } + failOnErrorEnabled = + !failOnErrorPackages.isEmpty() + ? ClassUtils.isClassBelowPackage(domainClazz, failOnErrorPackages) + : failOnError; validateParams = new HashMap(); validateParams.put(AbstractHibernateGormValidationApi.ARGUMENT_DEEP_VALIDATE, Boolean.FALSE); + } - try { - actionQueueUpdatesField = ReflectionUtils.findField(ActionQueue.class, "updates"); - actionQueueUpdatesField.setAccessible(true); - entityUpdateActionStateField = ReflectionUtils.findField(EntityUpdateAction.class, "state"); - entityUpdateActionStateField.setAccessible(true); - } catch (Exception ignored) { - // ignore + @Override + public void onPreLoad(PreLoadEvent event) { + if (preLoadEventCaller != null) { + doPreLoadWithManualSession(event, () -> preLoadEventCaller.call(event.getEntity())); } } - // public void onSaveOrUpdate(SaveOrUpdateEvent event) throws HibernateException { - // // no-op, merely a hook for plugins to override - // } - - public void onPreLoad(final PreLoadEvent event) { - if (preLoadEventCaller == null) { - return; + @Override + public void onPostLoad(PostLoadEvent event) { + if (postLoadEventListener != null) { + doPostLoadWithManualSession(event, () -> postLoadEventListener.call(event.getEntity())); } + } - doWithManualSession( + @Override + public boolean onPreInsert(PreInsertEvent event) { + return doBooleanWithManualSession( event, - new Closure(this) { - @Override - public Object call() { - preLoadEventCaller.call(event.getEntity()); - return null; + () -> { + Object entity = event.getEntity(); + if (beforeInsertCaller != null) { + if (beforeInsertCaller.call(entity)) return true; + synchronizePersisterState(event, event.getState()); } + return doValidate(entity); }); } - public void onPostLoad(final PostLoadEvent event) { - if (postLoadEventListener == null) { - return; - } + // --- Specific manual session versions for PreLoad and PostLoad --- - doWithManualSession( - event, - new Closure(this) { - @Override - public Object call() { - postLoadEventListener.call(event.getEntity()); - return null; - } - }); + private void doPreLoadWithManualSession(PreLoadEvent event, Runnable action) { + SharedSessionContractImplementor sessionImpl = event.getSession(); + if (sessionImpl instanceof Session session) { + FlushMode current = session.getHibernateFlushMode(); + try { + session.setHibernateFlushMode(FlushMode.MANUAL); + action.run(); + } finally { + session.setHibernateFlushMode(current); + } + } else { + action.run(); + } } - public void onPostInsert(PostInsertEvent event) { - final Object entity = event.getEntity(); - if (postInsertEventListener == null) { - return; + private void doPostLoadWithManualSession(PostLoadEvent event, Runnable action) { + SharedSessionContractImplementor sessionImpl = event.getSession(); + if (sessionImpl instanceof Session session) { + FlushMode current = session.getHibernateFlushMode(); + try { + session.setHibernateFlushMode(FlushMode.MANUAL); + action.run(); + } finally { + session.setHibernateFlushMode(current); + } + } else { + action.run(); } - - doWithManualSession( - event, - new Closure(this) { - @Override - public Object call() { - postInsertEventListener.call(entity); - return null; - } - }); } - // @Override - // public boolean requiresPostCommitHanding(EntityPersister persister) { - // return false; - // } + // --- Standard Overrides --- @Override - public boolean requiresPostCommitHandling(EntityPersister persister) { - return false; + public void onPostInsert(PostInsertEvent event) { + if (postInsertEventListener != null) { + doVoidWithManualSession(event, () -> postInsertEventListener.call(event.getEntity())); + } } + @Override public void onPostUpdate(PostUpdateEvent event) { - final Object entity = event.getEntity(); - if (postUpdateEventListener == null) { - return; + if (postUpdateEventListener != null) { + doVoidWithManualSession(event, () -> postUpdateEventListener.call(event.getEntity())); } - - doWithManualSession( - event, - new Closure(this) { - @Override - public Object call() { - postUpdateEventListener.call(entity); - return null; - } - }); } + @Override public void onPostDelete(PostDeleteEvent event) { - final Object entity = event.getEntity(); - if (postDeleteEventListener == null) { - return; + if (postDeleteEventListener != null) { + doVoidWithManualSession(event, () -> postDeleteEventListener.call(event.getEntity())); } - - doWithManualSession( - event, - new Closure(this) { - @Override - public Object call() { - postDeleteEventListener.call(entity); - return null; - } - }); } - public boolean onPreDelete(final PreDeleteEvent event) { - if (preDeleteEventListener == null) { - return false; - } - - return doWithManualSession( - event, - new Closure<Boolean>(this) { - @Override - public Boolean call() { - return preDeleteEventListener.call(event.getEntity()); - } - }); - } - - public boolean onPreUpdate(final PreUpdateEvent event) { - return doWithManualSession( - event, - new Closure<Boolean>(this) { - @Override - public Boolean call() { - Object entity = event.getEntity(); - boolean evict = false; - if (preUpdateEventListener != null) { - evict = preUpdateEventListener.call(entity); - if (!evict) { - synchronizePersisterState(event, event.getState()); - } - } - return evict || doValidate(entity); - } - }); + @Override + public boolean onPreDelete(PreDeleteEvent event) { + if (preDeleteEventListener == null) return false; + return doBooleanWithManualSession(event, () -> preDeleteEventListener.call(event.getEntity())); } - /** On pre insert. */ - public boolean onPreInsert(final PreInsertEvent event) { - return doWithManualSession( + @Override + public boolean onPreUpdate(PreUpdateEvent event) { + return doBooleanWithManualSession( event, - new Closure<Boolean>(this) { - @Override - public Boolean call() { - Object entity = event.getEntity(); - boolean synchronizeState = false; - if (beforeInsertCaller != null) { - if (beforeInsertCaller.call(entity)) { - return true; - } - synchronizeState = true; - } - if (synchronizeState) { + () -> { + Object entity = event.getEntity(); + boolean evict = false; + if (preUpdateEventListener != null) { + evict = preUpdateEventListener.call(entity); + if (!evict) { synchronizePersisterState(event, event.getState()); } - return doValidate(entity); } + return evict || doValidate(entity); }); } - /** On validate. */ public void onValidate(ValidationEvent event) { beforeValidateEventListener.call(event.getEntityObject(), event.getValidatedFields()); } - /** Do validate. */ protected boolean doValidate(Object entity) { - boolean evict = false; GormValidateable validateable = (GormValidateable) entity; if (!validateable.shouldSkipValidation() && !validateable.validate(validateParams)) { - evict = true; if (failOnErrorEnabled) { - Errors errors = validateable.getErrors(); throw ValidationException.newInstance( "Validation error whilst flushing entity [" + entity.getClass().getName() + "]", - errors); + validateable.getErrors()); } + return true; } - return evict; + return false; } private EventTriggerCaller buildCaller(String eventName, Class<?> domainClazz) { @@ -337,96 +241,70 @@ public class ClosureEventListener private void synchronizePersisterState(AbstractPreDatabaseOperationEvent event, Object[] state) { EntityPersister persister = event.getPersister(); - synchronizePersisterState(event, state, persister, persister.getPropertyNames()); - } - - private void synchronizePersisterState( - AbstractPreDatabaseOperationEvent event, - Object[] state, - EntityPersister persister, - String[] propertyNames) { Object entity = event.getEntity(); EntityReflector reflector = persistentEntity.getReflector(); - HashMap<Integer, Object> changedState = new HashMap<>(); EntityMappingType entityMappingType = persister.getEntityMappingType(); - for (int i = 0; i < propertyNames.length; i++) { - String p = propertyNames[i]; + String[] propertyNames = persister.getPropertyNames(); + + for (String p : propertyNames) { AttributeMapping attributeMapping = entityMappingType.findAttributeMapping(p); if (attributeMapping == null) continue; - int index = attributeMapping.getStateArrayPosition(); + int index = attributeMapping.getStateArrayPosition(); PersistentProperty property = persistentEntity.getPropertyByName(p); - if (property == null) { - continue; - } - String propertyName = property.getName(); - if (GormProperties.VERSION.equals(propertyName)) { - continue; + if (property != null && !GormProperties.VERSION.equals(property.getName())) { + state[index] = reflector.getProperty(entity, property.getName()); } + } + } - Object value = reflector.getProperty(entity, propertyName); - if (state[index] != value) { - changedState.put(i, value); + private void doVoidWithManualSession(AbstractEvent event, Runnable action) { + SharedSessionContractImplementor sessionImpl = event.getSession(); + if (sessionImpl instanceof Session session) { + FlushMode current = session.getHibernateFlushMode(); + try { + session.setHibernateFlushMode(FlushMode.MANUAL); + action.run(); + } finally { + session.setHibernateFlushMode(current); } - state[index] = value; + } else { + action.run(); } - - synchronizeEntityUpdateActionState(event, entity, changedState); } - private void synchronizeEntityUpdateActionState( - AbstractPreDatabaseOperationEvent event, - Object entity, - HashMap<Integer, Object> changedState) { - if (actionQueueUpdatesField != null - && event instanceof PreInsertEvent - && changedState.size() > 0) { + private boolean doBooleanWithManualSession(AbstractEvent event, Callable<Boolean> callable) { + SharedSessionContractImplementor sessionImpl = event.getSession(); + if (sessionImpl instanceof Session session) { + FlushMode current = session.getHibernateFlushMode(); try { - ExecutableList<EntityUpdateAction> updates = - (ExecutableList<EntityUpdateAction>) - actionQueueUpdatesField.get(event.getSession().getActionQueue()); - if (updates != null) { - for (EntityUpdateAction updateAction : updates) { - if (updateAction.getInstance() == entity) { - Object[] updateState = (Object[]) entityUpdateActionStateField.get(updateAction); - if (updateState != null) { - for (Map.Entry<Integer, Object> entry : changedState.entrySet()) { - updateState[entry.getKey()] = entry.getValue(); - } - } - } - } - } + session.setHibernateFlushMode(FlushMode.MANUAL); + return callable.call(); } catch (Exception e) { - LOG.warn("Error synchronizing object state with Hibernate: " + e.getMessage(), e); + throw new HibernateException(e); + } finally { + session.setHibernateFlushMode(current); } } - } - - private <T> T doWithManualSession(AbstractEvent event, Closure<T> callable) { - Session session = event.getSession(); - FlushMode current = session.getHibernateFlushMode(); try { - session.setHibernateFlushMode(FlushMode.MANUAL); return callable.call(); - } finally { - session.setHibernateFlushMode(current); + } catch (Exception e) { + throw new HibernateException(e); } } @Override - public void onMerge(MergeEvent event) throws HibernateException {} + public void onMerge(MergeEvent event) {} @Override - public void onMerge(MergeEvent event, MergeContext copiedAlready) throws HibernateException {} + public void onMerge(MergeEvent event, MergeContext copiedAlready) {} @Override - public void onPersist(PersistEvent event) throws HibernateException {} + public void onPersist(PersistEvent event) {} @Override - public void onPersist(PersistEvent event, PersistContext createdAlready) - throws HibernateException {} + public void onPersist(PersistEvent event, PersistContext createdAlready) {} @Override public void injectCallbackRegistry(CallbackRegistry callbackRegistry) {} diff --git a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java index 31ce6ad026..4ca7317583 100644 --- a/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java +++ b/grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/support/HibernateDialectDetectorFactoryBean.java @@ -193,6 +193,11 @@ public class HibernateDialectDetectorFactoryBean implements FactoryBean<String>, public ServiceRegistry getParentServiceRegistry() { return null; } + + @Override + public boolean isActive() { + return true; + } }); return factory; } diff --git a/grails-data-hibernate7/core/src/main/java/org/grails/orm/hibernate/cfg/domainbinding/util/GeneratorCreationContextWrapper.java b/grails-data-hibernate7/core/src/main/java/org/grails/orm/hibernate/cfg/domainbinding/util/GeneratorCreationContextWrapper.java new file mode 100644 index 0000000000..3f63b0cd4b --- /dev/null +++ b/grails-data-hibernate7/core/src/main/java/org/grails/orm/hibernate/cfg/domainbinding/util/GeneratorCreationContextWrapper.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * https://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.grails.orm.hibernate.cfg.domainbinding.util; + +import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.generator.GeneratorCreationContext; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; +import org.hibernate.mapping.RootClass; +import org.hibernate.mapping.Value; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; + +/** + * A wrapper for {@link GeneratorCreationContext} that allows overriding the {@link Value}. + */ +public class GeneratorCreationContextWrapper implements GeneratorCreationContext { + + private final GeneratorCreationContext delegate; + private final Value value; + + public GeneratorCreationContextWrapper(GeneratorCreationContext delegate, Value value) { + this.delegate = delegate; + this.value = value; + } + + @Override + public Database getDatabase() { + return delegate.getDatabase(); + } + + @Override + public ServiceRegistry getServiceRegistry() { + return delegate.getServiceRegistry(); + } + + @Override + public String getDefaultCatalog() { + return delegate.getDefaultCatalog(); + } + + @Override + public String getDefaultSchema() { + return delegate.getDefaultSchema(); + } + + @Override + public PersistentClass getPersistentClass() { + return delegate.getPersistentClass(); + } + + @Override + public RootClass getRootClass() { + return delegate.getRootClass(); + } + + @Override + public Property getProperty() { + return delegate.getProperty(); + } + + @Override + public Value getValue() { + return value != null ? value : delegate.getValue(); + } + + @Override + public Type getType() { + return delegate.getType(); + } + + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return delegate.getSqlStringGenerationContext(); + } +} diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy index 4ea6994586..4841c69f40 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/BasicValueIdCreatorSpec.groovy @@ -57,7 +57,7 @@ class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec { Generator generator = generatorCreator.createGenerator(context) then: - 1 * grailsSequenceWrapper.getGenerator(generatorName, context, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator + 1 * grailsSequenceWrapper.getGenerator(generatorName, _, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator generator == mockGenerator where: @@ -86,7 +86,7 @@ class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec { Generator generator = generatorCreator.createGenerator(context) then: - 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.NATIVE.toString(), context, null, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator + 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.NATIVE.toString(), _, null, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator generator == mockGenerator } @@ -102,7 +102,7 @@ class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec { Generator generator = generatorCreator.createGenerator(context) then: - 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.SEQUENCE_IDENTITY.toString(), context, null, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator + 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.SEQUENCE_IDENTITY.toString(), _, null, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator generator == mockGenerator } @@ -120,7 +120,7 @@ class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec { Generator generator = generatorCreator.createGenerator(context) then: - 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.SEQUENCE_IDENTITY.toString(), context, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator + 1 * grailsSequenceWrapper.getGenerator(GrailsSequenceGeneratorEnum.SEQUENCE_IDENTITY.toString(), _, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> mockGenerator generator == mockGenerator } @@ -137,6 +137,6 @@ class BasicValueIdCreatorSpec extends HibernateGormDatastoreSpec { generatorCreator.createGenerator(context) then: - 1 * grailsSequenceWrapper.getGenerator("custom", context, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> Mock(Generator) + 1 * grailsSequenceWrapper.getGenerator("custom", _, mappedId, domainClass, jdbcEnvironment, namingStrategy) >> Mock(Generator) } } diff --git a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/generator/GrailsSequenceGeneratorEnumSpec.groovy b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/generator/GrailsSequenceGeneratorEnumSpec.groovy index 0bf222974e..69fa1fe0a5 100644 --- a/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/generator/GrailsSequenceGeneratorEnumSpec.groovy +++ b/grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/generator/GrailsSequenceGeneratorEnumSpec.groovy @@ -23,7 +23,7 @@ import spock.lang.Shared import spock.lang.Unroll @Testcontainers -@Requires({ HibernateGormDatastoreSpec.isDockerAvailable() }) +@Requires({ isDockerAvailable() }) class GrailsSequenceGeneratorEnumSpec extends HibernateGormDatastoreSpec { @Shared PostgreSQLContainer postgres = new PostgreSQLContainer("postgres:16") @@ -52,9 +52,11 @@ class GrailsSequenceGeneratorEnumSpec extends HibernateGormDatastoreSpec { // Use the real PostgreSQL database from the running datastore so DDL type // registries (needed by TableGenerator.registerExportables) are correct. def db = datastore.metadata.database + def table = new org.hibernate.mapping.Table("grails_sequence_generator_enum_spec_entity") def column = new Column("id") def value = Mock(Value) { getColumns() >> [column] + getTable() >> table } def property = Mock(Property) { getName() >> "id" @@ -67,6 +69,7 @@ class GrailsSequenceGeneratorEnumSpec extends HibernateGormDatastoreSpec { getServiceRegistry() >> serviceRegistry getDatabase() >> db getProperty() >> property + getValue() >> value getType() >> type } }
