This is an automated email from the ASF dual-hosted git repository. borinquenkid pushed a commit to branch merge-hibernate6 in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 12d7be946a9a43b5b39ba4aa97c809c6c75d5cdb Author: Walter Duque de Estrada <[email protected]> AuthorDate: Sun Aug 10 00:03:30 2025 -0500 consolidate more classes --- .../grails/orm/hibernate/HibernateEntity.groovy | 8 +- .../AbstractHibernateGormStaticApi.groovy | 876 ------------ .../orm/hibernate/HibernateGormStaticApi.groovy | 752 +++++++++- .../query/AbstractHibernateCriteriaBuilder.java | 1496 -------------------- 4 files changed, 732 insertions(+), 2400 deletions(-) diff --git a/grails-data-hibernate6/core/src/main/groovy/grails/orm/hibernate/HibernateEntity.groovy b/grails-data-hibernate6/core/src/main/groovy/grails/orm/hibernate/HibernateEntity.groovy index 2c196d55d3..19e3822817 100644 --- a/grails-data-hibernate6/core/src/main/groovy/grails/orm/hibernate/HibernateEntity.groovy +++ b/grails-data-hibernate6/core/src/main/groovy/grails/orm/hibernate/HibernateEntity.groovy @@ -1,10 +1,10 @@ -package grails.gorm.hibernate +package grails.orm.hibernate import groovy.transform.CompileStatic import groovy.transform.Generated import org.grails.datastore.gorm.GormEnhancer import org.grails.datastore.gorm.GormEntity -import org.grails.orm.hibernate.AbstractHibernateGormStaticApi +import org.grails.orm.hibernate.HibernateGormStaticApi /** * Extends the {@link GormEntity} trait adding additional Hibernate specific methods @@ -62,7 +62,7 @@ trait HibernateEntity<D> extends GormEntity<D> { } @Generated - private static AbstractHibernateGormStaticApi currentHibernateStaticApi() { - (AbstractHibernateGormStaticApi)GormEnhancer.findStaticApi(this) + private static HibernateGormStaticApi currentHibernateStaticApi() { + (HibernateGormStaticApi)GormEnhancer.findStaticApi(this) } } \ No newline at end of file diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy deleted file mode 100644 index aa406787bb..0000000000 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/AbstractHibernateGormStaticApi.groovy +++ /dev/null @@ -1,876 +0,0 @@ -package org.grails.orm.hibernate - -import groovy.transform.CompileDynamic -import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j -import jakarta.persistence.NoResultException -import jakarta.persistence.criteria.Expression -import jakarta.persistence.criteria.Root -import org.grails.datastore.mapping.proxy.ProxyHandler -import org.grails.datastore.mapping.reflect.ClassUtils -import org.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder -import org.grails.orm.hibernate.cfg.CompositeIdentity -import org.grails.orm.hibernate.exceptions.GrailsQueryException - -import org.grails.orm.hibernate.query.HibernateHqlQuery -import org.grails.orm.hibernate.query.HibernateQuery -import org.grails.orm.hibernate.support.HibernateRuntimeUtils -import org.grails.datastore.gorm.GormStaticApi -import org.grails.datastore.gorm.finders.DynamicFinder -import org.grails.datastore.gorm.finders.FinderMethod -import org.hibernate.FlushMode -import org.hibernate.NonUniqueResultException -import org.hibernate.Session -import org.hibernate.jpa.QueryHints -import org.hibernate.query.NativeQuery -import org.hibernate.query.Query -import org.hibernate.query.criteria.JpaPredicate -import org.springframework.core.convert.ConversionService -import org.springframework.transaction.PlatformTransactionManager - -import jakarta.persistence.criteria.CriteriaBuilder -import jakarta.persistence.criteria.CriteriaQuery - -/** - * Abstract implementation of the Hibernate static API for GORM, providing String-based method implementations - * - * @author Graeme Rocher - * @since 4.0 - */ -@Slf4j -@CompileStatic -abstract class AbstractHibernateGormStaticApi<D> extends GormStaticApi<D> { - - - protected GrailsHibernateTemplate hibernateTemplate - protected ConversionService conversionService - protected final HibernateSession hibernateSession - ProxyHandler proxyHandler - -// AbstractHibernateGormStaticApi( -// Class<D> persistentClass, -// HibernateDatastore datastore, -// List<FinderMethod> finders) { -// this(persistentClass, datastore, finders, null) -// } - - AbstractHibernateGormStaticApi( - Class<D> persistentClass, - HibernateDatastore datastore, - List<FinderMethod> finders, - PlatformTransactionManager transactionManager) { - super(persistentClass, datastore, finders, transactionManager) - this.hibernateTemplate = new GrailsHibernateTemplate(datastore.getSessionFactory(), datastore) - this.conversionService = datastore.mappingContext.conversionService - this.proxyHandler = datastore.mappingContext.proxyHandler - this.hibernateSession = new HibernateSession( - (HibernateDatastore)datastore, - hibernateTemplate.getSessionFactory(), - hibernateTemplate.getFlushMode() - ) - } - - IHibernateTemplate getHibernateTemplate() { - return hibernateTemplate - } - - @Override - public <T> T withNewSession(Closure<T> callable) { - AbstractHibernateDatastore hibernateDatastore = (AbstractHibernateDatastore) datastore - hibernateDatastore.withNewSession(callable) - } - - @Override - def <T> T withSession(Closure<T> callable) { - AbstractHibernateDatastore hibernateDatastore = (AbstractHibernateDatastore) datastore - hibernateDatastore.withSession(callable) - } - - - @Override - D get(Serializable id) { - - if (id == null) { - return null - } - - id = convertIdentifier(id) - - if (id == null) { - return null - } - - if(persistentEntity.isMultiTenant()) { - // for multi-tenant entities we process get(..) via a query -// throw new UnsupportedOperationException("no yet") - (D)hibernateTemplate.execute( { Session session -> - - return new HibernateQuery(hibernateSession,persistentEntity ).idEq(id).singleResult() - } ) - } - else { - // for non multi-tenant entities we process get(..) via the second level cache - - hibernateTemplate.get(persistentEntity.javaClass, id) - - } - - } - - @Override - D read(Serializable id) { - if (id == null) { - return null - } - id = convertIdentifier(id) - - if (id == null) { - return null - } - - - (D)hibernateTemplate.execute( { Session session -> - CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(persistentEntity.javaClass) - - Root queryRoot = criteriaQuery.from(persistentEntity.javaClass) - criteriaQuery = criteriaQuery.where ( - //TODO: Remove explicit type cast once GROOVY-9460 - criteriaBuilder.equal((Expression<?>) queryRoot.get(persistentEntity.identity.name), id) - ) - Query criteria = session.createQuery(criteriaQuery) - .setHint(QueryHints.HINT_READONLY, true) - HibernateHqlQuery hibernateHqlQuery = new HibernateHqlQuery( - hibernateSession, persistentEntity, criteria) - return proxyHandler.unwrap( hibernateHqlQuery.singleResult() ) - - } ) - } - - @Override - D load(Serializable id) { - id = convertIdentifier(id) - if (id != null) { - return (D) hibernateTemplate.load((Class)persistentClass, id) - } - else { - return null - } - } - - - - @Override - List<D> getAll() { - (List<D>)hibernateTemplate.execute({ Session session -> - CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(persistentEntity.javaClass) - Query criteria = session.createQuery(criteriaQuery) - HibernateHqlQuery hibernateHqlQuery = new HibernateHqlQuery( - hibernateSession, persistentEntity, criteria) - return hibernateHqlQuery.list() - }) - } - - protected HibernateQuery createHibernateQuery() { - new HibernateQuery(hibernateSession, persistentEntity) - } - - @Override - Integer count() { - (Integer)hibernateTemplate.execute({ Session session -> - CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() - CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class) - criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(persistentEntity.javaClass))) - Query criteria = session.createQuery(criteriaQuery) - Long result =0 - try { - result = criteria.singleResult as Long - } catch (NonUniqueResultException nonUniqueResultException) { - log.warn(nonUniqueResultException.toString()) - } catch (NoResultException noResultException) { - log.warn(noResultException.toString()) - } - return result - }) - } - - /** - * Fire a post query event - * - * @param session The session - * @param criteria The criteria - * @param result The result - */ - protected abstract void firePostQueryEvent(Session session, CriteriaQuery criteria, Object result) - /** - * Fire a pre query event - * - * @param session The session - * @param criteria The criteria - * @return True if the query should be cancelled - */ - protected abstract void firePreQueryEvent(Session session, CriteriaQuery criteria) - - @Override - boolean exists(Serializable id) { - id = convertIdentifier(id) - hibernateTemplate.execute { Session session -> - return new HibernateQuery(hibernateSession,persistentEntity ).idEq(id).list().size() > 0 - } - } - - D first(Map m) { - def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass) - if (entityMapping?.identity instanceof CompositeIdentity) { - throw new UnsupportedOperationException('The first() method is not supported for domain classes that have composite keys.') - } - super.first(m) - } - - D last(Map m) { - def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass) - if (entityMapping?.identity instanceof CompositeIdentity) { - throw new UnsupportedOperationException('The last() method is not supported for domain classes that have composite keys.') - } - super.last(m) - } - - /** - * Implements the 'find(String' method to use HQL queries with named arguments - * - * @param query The query - * @param queryNamedArgs The named arguments - * @param args Any additional query arguments - * @return A result or null if no result found - */ - @Override - D find(CharSequence query, Map queryNamedArgs, Map args) { - queryNamedArgs = new LinkedHashMap(queryNamedArgs) - args = new LinkedHashMap(args) - if(query instanceof GString) { - query = buildNamedParameterQueryFromGString((GString) query, queryNamedArgs) - } - - String queryString = query.toString() - query = normalizeMultiLineQueryString(queryString) - - def template = hibernateTemplate - queryNamedArgs = new HashMap(queryNamedArgs) - return (D) template.execute { Session session -> - Query q = (Query) session.createQuery(queryString, persistentEntity.javaClass) - template.applySettings(q) - - populateQueryArguments(q, queryNamedArgs) - populateQueryArguments(q, args) - populateQueryWithNamedArguments(q, queryNamedArgs) - createHqlQuery(session, q).singleResult() - } - } - - protected abstract HibernateHqlQuery createHqlQuery(Session session, Query q) - - @Override - D find(CharSequence query, Collection params, Map args) { - if(query instanceof GString) { - throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped."); - } - - String queryString = query.toString() - queryString = normalizeMultiLineQueryString(queryString) - - args = new HashMap(args) - def template = hibernateTemplate - return (D) template.execute { Session session -> - Query q = (Query) session.createQuery(queryString, persistentEntity.javaClass) - template.applySettings(q) - - params.eachWithIndex { val, int i -> - if (val instanceof CharSequence) { - q.setParameter i, val.toString() - } - else { - q.setParameter i, val - } - } - populateQueryArguments(q, args) - createHqlQuery(session, q).singleResult() - } - } - - @Override - List<D> findAll(CharSequence query, Map params, Map args) { - params = new LinkedHashMap(params) - args = new LinkedHashMap(args) - if(query instanceof GString) { - query = buildNamedParameterQueryFromGString((GString) query, params) - } - - String queryString = query.toString() - queryString = normalizeMultiLineQueryString(queryString) - - def template = hibernateTemplate - return (List<D>) template.execute { Session session -> - Query q = (Query) session.createQuery(queryString) - template.applySettings(q) - - populateQueryArguments(q, params) - populateQueryArguments(q, args) - populateQueryWithNamedArguments(q, params) - - createHqlQuery(session, q).list() - } - } - - @CompileDynamic // required for Hibernate 5.2 compatibility - def <D> D findWithSql(CharSequence sql, Map args = Collections.emptyMap()) { - IHibernateTemplate template = hibernateTemplate - return (D) template.execute { Session session -> - - List params = [] - if(sql instanceof GString) { - sql = buildOrdinalParameterQueryFromGString((GString)sql, params) - } - - NativeQuery q = (NativeQuery)session.createNativeQuery(sql.toString()) - - template.applySettings(q) - - params.eachWithIndex { val, int i -> - i++ - if (val instanceof CharSequence) { - q.setParameter i, val.toString() - } - else { - q.setParameter i, val - } - } - q.addEntity(persistentClass) - populateQueryArguments(q, args) - q.setMaxResults(1) - def results = createHqlQuery(session, q).list() - if(results.isEmpty()) { - return null - } - else { - return results.get(0) - } - } - } - - /** - * Finds all results for this entity for the given SQL query - * - * @param sql The SQL query - * @param args The arguments - * @return All entities matching the SQL query - */ - @CompileDynamic // required for Hibernate 5.2 compatibility - List<D> findAllWithSql(CharSequence sql, Map args = Collections.emptyMap()) { - IHibernateTemplate template = hibernateTemplate - return (List<D>) template.execute { Session session -> - - List params = [] - if(sql instanceof GString) { - sql = buildOrdinalParameterQueryFromGString((GString)sql, params) - } - - NativeQuery q = (NativeQuery)session.createNativeQuery(sql.toString()) - - template.applySettings(q) - - params.eachWithIndex { val, int i -> - i++ - if (val instanceof CharSequence) { - q.setParameter i, val.toString() - } - else { - q.setParameter i, val - } - } - q.addEntity(persistentClass) - populateQueryArguments(q, args) - return createHqlQuery(session, q).list() - } - } - - @Override - List<D> findAll(CharSequence query) { - if(query instanceof GString) { - Map params = [:] - String hql = buildNamedParameterQueryFromGString((GString)query, params) - return findAll(hql, params, Collections.emptyMap()) - } - else { - return super.findAll(query) - } - } - - @Override - List executeQuery(CharSequence query) { - if(query instanceof GString) { - Map params = [:] - String hql = buildNamedParameterQueryFromGString((GString)query, params) - return executeQuery(hql, params, Collections.emptyMap()) - } - else { - return super.executeQuery(query) - } - } - - @Override - Integer executeUpdate(CharSequence query) { - if(query instanceof GString) { - Map params = [:] - String hql = buildNamedParameterQueryFromGString((GString)query, params) - return executeUpdate(hql, params, Collections.emptyMap()) - } - else { - return super.executeUpdate(query) - } - } - - @Override - D find(CharSequence query) { - if(query instanceof GString) { - Map params = [:] - String hql = buildNamedParameterQueryFromGString((GString)query, params) - return find(hql, params, Collections.emptyMap()) - } - else { - return (D)super.find(query) - } - } - - @Override - D find(CharSequence query, Map params) { - if(query instanceof GString) { - Map newParams = new LinkedHashMap(params) - String hql = buildNamedParameterQueryFromGString((GString)query, newParams) - return find(hql, newParams, newParams) - } - else { - return (D)super.find(query, params) - } - } - - - - @Override - List<D> findAll(CharSequence query, Map params) { - if(query instanceof GString) { - Map newParams = new LinkedHashMap(params) - String hql = buildNamedParameterQueryFromGString((GString)query, newParams) - return findAll(hql, newParams, newParams) - } - else { - return super.findAll(query, params) - } - } - - @Override - List executeQuery(CharSequence query, Map args) { - if(query instanceof GString) { - Map newParams = new LinkedHashMap(args) - String hql = buildNamedParameterQueryFromGString((GString)query, newParams) - return executeQuery(hql, newParams, newParams) - } - else { - return super.executeQuery(query, args) - } - } - - @Override - Integer executeUpdate(CharSequence query, Map args) { - if(query instanceof GString) { - Map newParams = new LinkedHashMap(args) - String hql = buildNamedParameterQueryFromGString((GString)query, newParams) - return executeUpdate(hql, newParams, newParams) - } - else { - return super.executeUpdate(query, args) - } - } - - @Override - List<D> findAll(CharSequence query, Collection params, Map args) { - if(query instanceof GString) { - throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped.") - } - - String queryString = query.toString() - queryString = normalizeMultiLineQueryString(queryString) - - args = new HashMap(args) - - def template = hibernateTemplate - return (List<D>) template.execute { Session session -> - Query q = (Query) session.createQuery(queryString) - template.applySettings(q) - - params.eachWithIndex { val, int i -> - if (val instanceof CharSequence) { - q.setParameter i, val.toString() - } - else { - q.setParameter i, val - } - } - populateQueryArguments(q, args) - createHqlQuery(session, q).list() - } - } - - @Override - D find(D exampleObject, Map args) { - throw new UnsupportedOperationException("not yet") -// def template = hibernateTemplate -// return (D) template.execute { Session session -> -// Example example = Example.create(exampleObject).ignoreCase() -// -// Criteria crit = session.createCriteria(persistentEntity.javaClass); -// hibernateTemplate.applySettings(crit) -// crit.add example -// GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, crit, args, datastore.mappingContext.conversionService, true) -// crit.maxResults = 1 -// firePreQueryEvent(session, crit) -// List results = crit.list() -// firePostQueryEvent(session, crit, results) -// if (results) { -// return proxyHandler.unwrap( results.get(0) ) -// } -// } - } - - @Override - List<D> findAll(D exampleObject, Map args) { - throw new UnsupportedOperationException("Example is not supported but maybe in the future") -// def template = hibernateTemplate -// return (List<D>) template.execute { Session session -> -// Example example = Example.create(exampleObject).ignoreCase() -// -// Criteria crit = session.createCriteria(persistentEntity.javaClass); -// hibernateTemplate.applySettings(crit) -// crit.add example -// GrailsHibernateQueryUtils.populateArgumentsForCriteria(persistentEntity, crit, args, datastore.mappingContext.conversionService, true) -// firePreQueryEvent(session, crit) -// List results = crit.list() -// firePostQueryEvent(session, crit, results) -// return results -// } - } - - @Override - List<D> findAllWhere(Map queryMap, Map args) { - if (!queryMap) return null - (List<D>)hibernateTemplate.execute { Session session -> - Map<String, Object> processedQueryMap = [:] - queryMap.each{ key, value -> processedQueryMap[key.toString()] = value } - Map<String,Object> queryArgs = filterQueryArgumentMap(processedQueryMap) - List<String> nullNames = removeNullNames(queryArgs) - - CriteriaBuilder cb = session.getCriteriaBuilder() - CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) - def root = cq.from(persistentEntity.javaClass) - def listOfPredicates = queryArgs.collect { entry -> cb.equal(root.get(entry.key), entry.value) } - def nullPredicates = nullNames.collect { nullName -> cb.isNotNull(root.get(nullName))} - def jpaPredicates = (listOfPredicates + nullPredicates).<JpaPredicate>toArray(new JpaPredicate[0]) - cq.select(root).where(cb.and(jpaPredicates)) - firePreQueryEvent(session, cq) - List results = session.createQuery(cq).resultList - firePostQueryEvent(session, cq, results) - return results - } - } - - - @Override - List executeQuery(CharSequence query, Map params, Map args) { - def template = hibernateTemplate - args = new HashMap(args) - params = new HashMap(params) - - if(query instanceof GString) { - query = buildNamedParameterQueryFromGString((GString) query, params) - } - - return (List<D>) template.execute { Session session -> - //TODO Right now making the return type of Object.class to execute arbitrary queries - // not sure if this will work for projections - Query q = (Query) session.createQuery(query.toString(),Object.class) - template.applySettings(q) - - populateQueryArguments(q, params) - populateQueryArguments(q, args) - populateQueryWithNamedArguments(q, params) - - createHqlQuery(session, q).list() - } - } - - @Override - List executeQuery(CharSequence query, Collection params, Map args) { - if(query instanceof GString) { - throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped."); - } - - def template = hibernateTemplate - args = new HashMap(args) - - return (List<D>) template.execute { Session session -> - Query q = (Query) session.createQuery(query.toString(),persistentEntity.javaClass) - template.applySettings(q) - - params.eachWithIndex { val, int i -> - if (val instanceof CharSequence) { - q.setParameter i, val.toString() - } - else { - q.setParameter i, val - } - } - populateQueryArguments(q, args) - createHqlQuery(session, q).list() - } - } - - @Override - D findWhere(Map queryMap, Map args) { - if (!queryMap) return null - (D)hibernateTemplate.execute { Session session -> - Map<String, Object> processedQueryMap = [:] - queryMap.each{ key, value -> processedQueryMap[key.toString()] = value } - Map<String,Object> queryArgs = filterQueryArgumentMap(processedQueryMap) - List<String> nullNames = removeNullNames(queryArgs) - CriteriaBuilder cb = session.getCriteriaBuilder() - CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) - def root = cq.from(persistentEntity.javaClass) - def listOfPredicates = queryArgs.collect { entry -> cb.equal(root.get(entry.key), entry.value) } - def nullPredicates = nullNames.collect { nullName -> cb.isNotNull(root.get(nullName)) } - JpaPredicate[] jpaPredicates = (listOfPredicates + nullPredicates).<JpaPredicate>toArray(new JpaPredicate[0]) - cq.select(root).where(cb.and(jpaPredicates)) - firePreQueryEvent(session, cq) - Object result = session.createQuery(cq).singleResult - firePostQueryEvent(session, cq, result) - result - } - } - - List<D> getAll(List ids) { - getAllInternal(ids) - } - - - - List<D> getAll(Long... ids) { - getAllInternal(ids as List) - } - - @Override - List<D> getAll(Serializable... ids) { - getAllInternal(ids as List) - } - - @CompileDynamic - private List getAllInternal(List ids) { - if (!ids) return [] - - (List)hibernateTemplate.execute { Session session -> - def identityType = persistentEntity.identity.type - def identityName = persistentEntity.identity.name - List<Object> convertedIds = ids.collect { HibernateRuntimeUtils.convertValueToType((Serializable)it, identityType, conversionService) } - CriteriaBuilder cb = session.getCriteriaBuilder() - CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) - def root = cq.from(persistentEntity.javaClass) - cq.select(root).where(root.get("id").in(convertedIds)) - firePreQueryEvent(session, cq) - - List results = session.createQuery(cq).resultList - firePostQueryEvent(session, cq, results) - def idsMap = [:] - for (object in results) { - idsMap[object[identityName]] = object - } - results.clear() - for (id in ids) { - results << idsMap[id] - } - results - } - } - - protected Map<String,Object> filterQueryArgumentMap(Map<String,Object> query) { - Map<String,Object> queryArgs = new HashMap<>() - for (entry in query.entrySet()) { - if (entry.value instanceof CharSequence) { - queryArgs[entry.key] = entry.value.toString() - } - else { - queryArgs[entry.key] = entry.value - } - } - return queryArgs - } - - /** - * Processes a query converting GString expressions into parameters - * - * @param query The query - * @param params The parameters - * @return The final String - */ - protected String buildOrdinalParameterQueryFromGString(GString query, List params) { - StringBuilder sqlString = new StringBuilder() - int i = 0 - Object[] values = query.values - def strings = query.getStrings() - for (str in strings) { - sqlString.append(str) - if (i < values.length) { - sqlString.append('?') - params.add(values[i++]) - } - } - return sqlString.toString() - } - - /** - * Processes a query converting GString expressions into parameters - * - * @param query The query - * @param params The parameters - * @return The final String - */ - protected String buildNamedParameterQueryFromGString(GString query, Map params) { - StringBuilder sqlString = new StringBuilder() - int i = 0 - Object[] values = query.values - def strings = query.getStrings() - for (str in strings) { - sqlString.append(str) - if (i < values.length) { - String parameterName = "p$i" - sqlString.append(':').append(parameterName) - params.put(parameterName, values[i++]) - } - } - return sqlString.toString() - } - - protected List<String> removeNullNames(Map query) { - List<String> nullNames = [] - Set<String> allNames = new HashSet<>(query.keySet() as Set<String>) - for (String name in allNames) { - if (query[name] == null) { - query.remove name - nullNames << name - } - } - nullNames - } - - protected Serializable convertIdentifier(Serializable id) { - def identity = persistentEntity.identity - if(identity != null) { - ConversionService conversionService = persistentEntity.mappingContext.conversionService - if(id != null) { - Class identityType = identity.type - Class idInstanceType = id.getClass() - if(identityType.isAssignableFrom(idInstanceType)) { - return id - } - else if(conversionService.canConvert(idInstanceType, identityType)) { - try { - return (Serializable)conversionService.convert(id, identityType) - } catch (Throwable e) { - // unconvertable id, return null - return null - } - } - else { - // unconvertable id, return null - return null - } - } - } - return id - } - - protected void populateQueryWithNamedArguments(Query q, Map queryNamedArgs) { - - if (queryNamedArgs) { - for (Map.Entry entry in queryNamedArgs.entrySet()) { - def key = entry.key - if (!(key instanceof CharSequence)) { - throw new GrailsQueryException("Named parameter's name must be String: $queryNamedArgs") - } - String stringKey = key.toString() - def value = entry.value - - if(value == null) { - q.setParameter stringKey, null - } else if (value instanceof CharSequence) { - q.setParameter stringKey, value.toString() - } else if (List.class.isAssignableFrom(value.getClass())) { - q.setParameterList stringKey, (List) value - } else if (Set.class.isAssignableFrom(value.getClass())) { - q.setParameterList stringKey, (Set) value - } else if (value.getClass().isArray()) { - q.setParameterList stringKey, (Object[]) value - } else { - q.setParameter stringKey, value - } - } - } - } - - protected Integer intValue(Map args, String key) { - def value = args.get(key) - if(value) { - return conversionService.convert(value, Integer.class) - } - return null - } - - protected void populateQueryArguments(Query q, Map args) { - Integer max = intValue(args, DynamicFinder.ARGUMENT_MAX) - args.remove(DynamicFinder.ARGUMENT_MAX) - Integer offset = intValue(args, DynamicFinder.ARGUMENT_OFFSET) - args.remove(DynamicFinder.ARGUMENT_OFFSET) - - // - if (max != null) { - q.maxResults = max - } - if (offset != null) { - q.firstResult = offset - } - - if (args.containsKey(DynamicFinder.ARGUMENT_CACHE)) { - q.cacheable = ClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_CACHE, args) - } - if (args.containsKey(DynamicFinder.ARGUMENT_FETCH_SIZE)) { - Integer fetchSizeParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_FETCH_SIZE), Integer.class); - q.setFetchSize(fetchSizeParam.intValue()); - } - if (args.containsKey(DynamicFinder.ARGUMENT_TIMEOUT)) { - Integer timeoutParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_TIMEOUT), Integer.class); - q.setTimeout(timeoutParam.intValue()); - } - if (args.containsKey(DynamicFinder.ARGUMENT_READ_ONLY)) { - q.setReadOnly((Boolean)args.remove(DynamicFinder.ARGUMENT_READ_ONLY)); - } - if (args.containsKey(DynamicFinder.ARGUMENT_FLUSH_MODE)) { - q.setHibernateFlushMode((FlushMode)args.remove(DynamicFinder.ARGUMENT_FLUSH_MODE)); - } - - args.remove(DynamicFinder.ARGUMENT_CACHE) - } - - private String normalizeMultiLineQueryString(String query) { - if (query.indexOf('\n') != -1) - return query.trim().replace('\n', ' ') - return query - } - -} diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy index 515cda5eef..d229cc78c6 100644 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy +++ b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/HibernateGormStaticApi.groovy @@ -16,20 +16,38 @@ package org.grails.orm.hibernate import grails.orm.HibernateCriteriaBuilder +import groovy.transform.CompileDynamic import groovy.transform.CompileStatic +import groovy.util.logging.Slf4j +import jakarta.persistence.NoResultException +import jakarta.persistence.criteria.Expression +import jakarta.persistence.criteria.Root import org.grails.datastore.gorm.GormEnhancer +import org.grails.datastore.gorm.GormStaticApi import org.grails.datastore.gorm.finders.DynamicFinder import org.grails.datastore.gorm.finders.FinderMethod import org.grails.datastore.mapping.query.api.BuildableCriteria as GrailsCriteria import org.grails.datastore.mapping.query.event.PostQueryEvent import org.grails.datastore.mapping.query.event.PreQueryEvent +import org.grails.datastore.mapping.proxy.ProxyHandler +import org.grails.datastore.mapping.reflect.ClassUtils +import org.grails.orm.hibernate.cfg.AbstractGrailsDomainBinder +import org.grails.orm.hibernate.cfg.CompositeIdentity import org.grails.orm.hibernate.exceptions.GrailsQueryException import org.grails.orm.hibernate.query.GrailsHibernateQueryUtils import org.grails.orm.hibernate.query.HibernateHqlQuery -import org.grails.orm.hibernate.query.PagedResultList import org.grails.orm.hibernate.query.HibernateQuery -import org.hibernate.* +import org.grails.orm.hibernate.query.PagedResultList +import org.grails.orm.hibernate.support.HibernateRuntimeUtils +import org.hibernate.FlushMode +import org.hibernate.LockMode +import org.hibernate.NonUniqueResultException +import org.hibernate.Session +import org.hibernate.SessionFactory +import org.hibernate.jpa.QueryHints +import org.hibernate.query.NativeQuery import org.hibernate.query.Query +import org.hibernate.query.criteria.JpaPredicate import org.springframework.core.convert.ConversionService import org.springframework.orm.hibernate5.SessionHolder import org.springframework.transaction.PlatformTransactionManager @@ -38,7 +56,6 @@ import org.springframework.transaction.support.TransactionSynchronizationManager import jakarta.persistence.FlushModeType import jakarta.persistence.criteria.CriteriaBuilder import jakarta.persistence.criteria.CriteriaQuery -import jakarta.persistence.criteria.Root /** * The implementation of the GORM static method contract for Hibernate @@ -46,30 +63,728 @@ import jakarta.persistence.criteria.Root * @author Graeme Rocher * @since 1.0 */ +@Slf4j @CompileStatic -class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { - protected SessionFactory sessionFactory +class HibernateGormStaticApi<D> extends GormStaticApi<D> { + + protected GrailsHibernateTemplate hibernateTemplate protected ConversionService conversionService + protected final HibernateSession hibernateSession + protected ProxyHandler proxyHandler + protected SessionFactory sessionFactory protected Class identityType protected ClassLoader classLoader private HibernateGormInstanceApi<D> instanceApi private int defaultFlushMode HibernateGormStaticApi(Class<D> persistentClass, HibernateDatastore datastore, List<FinderMethod> finders, - ClassLoader classLoader, PlatformTransactionManager transactionManager) { + ClassLoader classLoader, PlatformTransactionManager transactionManager) { super(persistentClass, datastore, finders, transactionManager) + this.hibernateTemplate = new GrailsHibernateTemplate(datastore.getSessionFactory(), datastore) + this.conversionService = datastore.mappingContext.conversionService + this.proxyHandler = datastore.mappingContext.proxyHandler + this.hibernateSession = new HibernateSession( + (HibernateDatastore)datastore, + hibernateTemplate.getSessionFactory(), + hibernateTemplate.getFlushMode() + ) this.classLoader = classLoader - sessionFactory = datastore.getSessionFactory() - conversionService = datastore.mappingContext.conversionService - - identityType = persistentEntity.identity?.type + this.sessionFactory = datastore.getSessionFactory() + this.identityType = persistentEntity.identity?.type this.defaultFlushMode = datastore.getDefaultFlushMode() - instanceApi = new HibernateGormInstanceApi<>(persistentClass, datastore, classLoader) + this.instanceApi = new HibernateGormInstanceApi<>(persistentClass, datastore, classLoader) } - @Override GrailsHibernateTemplate getHibernateTemplate() { - return (GrailsHibernateTemplate)super.getHibernateTemplate() + return hibernateTemplate as GrailsHibernateTemplate + } + + @Override + public <T> T withNewSession(Closure<T> callable) { + AbstractHibernateDatastore hibernateDatastore = (AbstractHibernateDatastore) datastore + hibernateDatastore.withNewSession(callable) + } + + @Override + def <T> T withSession(Closure<T> callable) { + AbstractHibernateDatastore hibernateDatastore = (AbstractHibernateDatastore) datastore + hibernateDatastore.withSession(callable) + } + + D get(Serializable id) { + if (id == null) { + return null + } + + id = convertIdentifier(id) + + if (id == null) { + return null + } + + if(persistentEntity.isMultiTenant()) { + // for multi-tenant entities we process get(..) via a query + (D)hibernateTemplate.execute( { Session session -> + return new HibernateQuery(hibernateSession,persistentEntity ).idEq(id).singleResult() + } ) + } + else { + // for non multi-tenant entities we process get(..) via the second level cache + hibernateTemplate.get(persistentEntity.javaClass, id) + } + } + + D read(Serializable id) { + if (id == null) { + return null + } + id = convertIdentifier(id) + + if (id == null) { + return null + } + + (D)hibernateTemplate.execute( { Session session -> + CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(persistentEntity.javaClass) + + Root queryRoot = criteriaQuery.from(persistentEntity.javaClass) + criteriaQuery = criteriaQuery.where ( + //TODO: Remove explicit type cast once GROOVY-9460 + criteriaBuilder.equal((Expression<?>) queryRoot.get(persistentEntity.identity.name), id) + ) + Query criteria = session.createQuery(criteriaQuery) + .setHint(QueryHints.HINT_READONLY, true) + HibernateHqlQuery hibernateHqlQuery = new HibernateHqlQuery( + hibernateSession, persistentEntity, criteria) + return proxyHandler.unwrap( hibernateHqlQuery.singleResult() ) + } ) + } + + @Override + D load(Serializable id) { + id = convertIdentifier(id) + if (id != null) { + return (D) hibernateTemplate.load((Class)persistentClass, id) + } + else { + return null + } + } + + @Override + List<D> getAll() { + (List<D>)hibernateTemplate.execute({ Session session -> + CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(persistentEntity.javaClass) + Query criteria = session.createQuery(criteriaQuery) + HibernateHqlQuery hibernateHqlQuery = new HibernateHqlQuery( + hibernateSession, persistentEntity, criteria) + return hibernateHqlQuery.list() + }) + } + + protected HibernateQuery createHibernateQuery() { + new HibernateQuery(hibernateSession, persistentEntity) + } + + @Override + Integer count() { + (Integer)hibernateTemplate.execute({ Session session -> + CriteriaBuilder criteriaBuilder = session.getCriteriaBuilder() + CriteriaQuery criteriaQuery = criteriaBuilder.createQuery(Long.class) + criteriaQuery.select(criteriaBuilder.count(criteriaQuery.from(persistentEntity.javaClass))) + Query criteria = session.createQuery(criteriaQuery) + Long result =0 + try { + result = criteria.singleResult as Long + } catch (NonUniqueResultException nonUniqueResultException) { + log.warn(nonUniqueResultException.toString()) + } catch (NoResultException noResultException) { + log.warn(noResultException.toString()) + } + return result + }) + } + + @Override + boolean exists(Serializable id) { + id = convertIdentifier(id) + hibernateTemplate.execute { Session session -> + return new HibernateQuery(hibernateSession,persistentEntity ).idEq(id).list().size() > 0 + } + } + + @Override + D first(Map m) { + def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass) + if (entityMapping?.identity instanceof CompositeIdentity) { + throw new UnsupportedOperationException('The first() method is not supported for domain classes that have composite keys.') + } + super.first(m) + } + + @Override + D last(Map m) { + def entityMapping = AbstractGrailsDomainBinder.getMapping(persistentEntity.javaClass) + if (entityMapping?.identity instanceof CompositeIdentity) { + throw new UnsupportedOperationException('The last() method is not supported for domain classes that have composite keys.') + } + super.last(m) + } + + @Override + D find(CharSequence query, Map queryNamedArgs, Map args) { + queryNamedArgs = new LinkedHashMap(queryNamedArgs) + args = new LinkedHashMap(args) + if(query instanceof GString) { + query = buildNamedParameterQueryFromGString((GString) query, queryNamedArgs) + } + + String queryString = query.toString() + query = normalizeMultiLineQueryString(queryString) + + def template = hibernateTemplate + queryNamedArgs = new HashMap(queryNamedArgs) + return (D) template.execute { Session session -> + Query q = (Query) session.createQuery(queryString, persistentEntity.javaClass) + template.applySettings(q) + + populateQueryArguments(q, queryNamedArgs) + populateQueryArguments(q, args) + populateQueryWithNamedArguments(q, queryNamedArgs) + createHqlQuery(session, q).singleResult() + } + } + + @Override + D find(CharSequence query, Collection params, Map args) { + if(query instanceof GString) { + throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped."); + } + + String queryString = query.toString() + queryString = normalizeMultiLineQueryString(queryString) + + args = new HashMap(args) + def template = hibernateTemplate + return (D) template.execute { Session session -> + Query q = (Query) session.createQuery(queryString, persistentEntity.javaClass) + template.applySettings(q) + + params.eachWithIndex { val, int i -> + if (val instanceof CharSequence) { + q.setParameter i, val.toString() + } + else { + q.setParameter i, val + } + } + populateQueryArguments(q, args) + createHqlQuery(session, q).singleResult() + } + } + + @Override + List<D> findAll(CharSequence query, Map params, Map args) { + params = new LinkedHashMap(params) + args = new LinkedHashMap(args) + if(query instanceof GString) { + query = buildNamedParameterQueryFromGString((GString) query, params) + } + + String queryString = query.toString() + queryString = normalizeMultiLineQueryString(queryString) + + def template = hibernateTemplate + return (List<D>) template.execute { Session session -> + Query q = (Query) session.createQuery(queryString) + template.applySettings(q) + + populateQueryArguments(q, params) + populateQueryArguments(q, args) + populateQueryWithNamedArguments(q, params) + + createHqlQuery(session, q).list() + } + } + + @CompileDynamic // required for Hibernate 5.2 compatibility + def <D> D findWithSql(CharSequence sql, Map args = Collections.emptyMap()) { + IHibernateTemplate template = hibernateTemplate + return (D) template.execute { Session session -> + + List params = [] + if(sql instanceof GString) { + sql = buildOrdinalParameterQueryFromGString((GString)sql, params) + } + + NativeQuery q = (NativeQuery)session.createNativeQuery(sql.toString()) + + template.applySettings(q) + + params.eachWithIndex { val, int i -> + i++ + if (val instanceof CharSequence) { + q.setParameter i, val.toString() + } + else { + q.setParameter i, val + } + } + q.addEntity(persistentClass) + populateQueryArguments(q, args) + q.setMaxResults(1) + def results = createHqlQuery(session, q).list() + if(results.isEmpty()) { + return null + } + else { + return results.get(0) + } + } + } + + @CompileDynamic // required for Hibernate 5.2 compatibility + List<D> findAllWithSql(CharSequence sql, Map args = Collections.emptyMap()) { + IHibernateTemplate template = hibernateTemplate + return (List<D>) template.execute { Session session -> + + List params = [] + if(sql instanceof GString) { + sql = buildOrdinalParameterQueryFromGString((GString)sql, params) + } + + NativeQuery q = (NativeQuery)session.createNativeQuery(sql.toString()) + + template.applySettings(q) + + params.eachWithIndex { val, int i -> + i++ + if (val instanceof CharSequence) { + q.setParameter i, val.toString() + } + else { + q.setParameter i, val + } + } + q.addEntity(persistentClass) + populateQueryArguments(q, args) + return createHqlQuery(session, q).list() + } + } + + @Override + List<D> findAll(CharSequence query) { + if(query instanceof GString) { + Map params = [:] + String hql = buildNamedParameterQueryFromGString((GString)query, params) + return findAll(hql, params, Collections.emptyMap()) + } + else { + return super.findAll(query) + } + } + + @Override + List executeQuery(CharSequence query) { + if(query instanceof GString) { + Map params = [:] + String hql = buildNamedParameterQueryFromGString((GString)query, params) + return executeQuery(hql, params, Collections.emptyMap()) + } + else { + return super.executeQuery(query) + } + } + + @Override + Integer executeUpdate(CharSequence query) { + if(query instanceof GString) { + Map params = [:] + String hql = buildNamedParameterQueryFromGString((GString)query, params) + return executeUpdate(hql, params, Collections.emptyMap()) + } + else { + return super.executeUpdate(query) + } + } + + @Override + D find(CharSequence query) { + if(query instanceof GString) { + Map params = [:] + String hql = buildNamedParameterQueryFromGString((GString)query, params) + return find(hql, params, Collections.emptyMap()) + } + else { + return (D)super.find(query) + } + } + + @Override + D find(CharSequence query, Map params) { + if(query instanceof GString) { + Map newParams = new LinkedHashMap(params) + String hql = buildNamedParameterQueryFromGString((GString)query, newParams) + return find(hql, newParams, newParams) + } + else { + return (D)super.find(query, params) + } + } + + @Override + List<D> findAll(CharSequence query, Map params) { + if(query instanceof GString) { + Map newParams = new LinkedHashMap(params) + String hql = buildNamedParameterQueryFromGString((GString)query, newParams) + return findAll(hql, newParams, newParams) + } + else { + return super.findAll(query, params) + } + } + + @Override + List executeQuery(CharSequence query, Map args) { + if(query instanceof GString) { + Map newParams = new LinkedHashMap(args) + String hql = buildNamedParameterQueryFromGString((GString)query, newParams) + return executeQuery(hql, newParams, newParams) + } + else { + return super.executeQuery(query, args) + } + } + + @Override + List<D> findAll(CharSequence query, Collection params, Map args) { + if(query instanceof GString) { + throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped."); + } + + String queryString = query.toString() + queryString = normalizeMultiLineQueryString(queryString) + + args = new HashMap(args) + + def template = hibernateTemplate + return (List<D>) template.execute { Session session -> + Query q = (Query) session.createQuery(queryString) + template.applySettings(q) + + params.eachWithIndex { val, int i -> + if (val instanceof CharSequence) { + q.setParameter i, val.toString() + } + else { + q.setParameter i, val + } + } + populateQueryArguments(q, args) + createHqlQuery(session, q).list() + } + } + + @Override + D find(D exampleObject, Map args) { + throw new UnsupportedOperationException("not yet") + } + + @Override + List<D> findAll(D exampleObject, Map args) { + throw new UnsupportedOperationException("Example is not supported but maybe in the future") + } + + @Override + List<D> findAllWhere(Map queryMap, Map args) { + if (!queryMap) return null + (List<D>)hibernateTemplate.execute { Session session -> + Map<String, Object> processedQueryMap = [:] + queryMap.each{ key, value -> processedQueryMap[key.toString()] = value } + Map<String,Object> queryArgs = filterQueryArgumentMap(processedQueryMap) + List<String> nullNames = removeNullNames(queryArgs) + + CriteriaBuilder cb = session.getCriteriaBuilder() + CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) + def root = cq.from(persistentEntity.javaClass) + def listOfPredicates = queryArgs.collect { entry -> cb.equal(root.get(entry.key), entry.value) } + def nullPredicates = nullNames.collect { nullName -> cb.isNotNull(root.get(nullName)) } + def jpaPredicates = (listOfPredicates + nullPredicates).<JpaPredicate>toArray(new JpaPredicate[0]) + cq.select(root).where(cb.and(jpaPredicates)) + firePreQueryEvent(session, cq) + List results = session.createQuery(cq).resultList + firePostQueryEvent(session, cq, results) + return results + } + } + + @Override + List executeQuery(CharSequence query, Map params, Map args) { + def template = hibernateTemplate + args = new HashMap(args) + params = new HashMap(params) + + if(query instanceof GString) { + query = buildNamedParameterQueryFromGString((GString) query, params) + } + + return (List<D>) template.execute { Session session -> + Query q = (Query) session.createQuery(query.toString(),Object.class) + template.applySettings(q) + + populateQueryArguments(q, params) + populateQueryArguments(q, args) + populateQueryWithNamedArguments(q, params) + + createHqlQuery(session, q).list() + } + } + + @Override + List executeQuery(CharSequence query, Collection params, Map args) { + if(query instanceof GString) { + throw new GrailsQueryException("Unsafe query [$query]. GORM cannot automatically escape a GString value when combined with ordinal parameters, so this query is potentially vulnerable to HQL injection attacks. Please embed the parameters within the GString so they can be safely escaped."); + } + + def template = hibernateTemplate + args = new HashMap(args) + + return (List<D>) template.execute { Session session -> + Query q = (Query) session.createQuery(query.toString(),persistentEntity.javaClass) + template.applySettings(q) + + params.eachWithIndex { val, int i -> + if (val instanceof CharSequence) { + q.setParameter i, val.toString() + } + else { + q.setParameter i, val + } + } + populateQueryArguments(q, args) + createHqlQuery(session, q).list() + } + } + + @Override + D findWhere(Map queryMap, Map args) { + if (!queryMap) return null + (D)hibernateTemplate.execute { Session session -> + Map<String, Object> processedQueryMap = [:] + queryMap.each{ key, value -> processedQueryMap[key.toString()] = value } + Map<String,Object> queryArgs = filterQueryArgumentMap(processedQueryMap) + List<String> nullNames = removeNullNames(queryArgs) + CriteriaBuilder cb = session.getCriteriaBuilder() + CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) + def root = cq.from(persistentEntity.javaClass) + def listOfPredicates = queryArgs.collect { entry -> cb.equal(root.get(entry.key), entry.value) } + def nullPredicates = nullNames.collect { nullName -> cb.isNotNull(root.get(nullName)) } + JpaPredicate[] jpaPredicates = (listOfPredicates + nullPredicates).<JpaPredicate>toArray(new JpaPredicate[0]) + cq.select(root).where(cb.and(jpaPredicates)) + firePreQueryEvent(session, cq) + Object result = session.createQuery(cq).singleResult + firePostQueryEvent(session, cq, result) + result + } + } + + List<D> getAll(List ids) { + getAllInternal(ids) + } + + List<D> getAll(Long... ids) { + getAllInternal(ids as List) + } + + @Override + List<D> getAll(Serializable... ids) { + getAllInternal(ids as List) + } + + @CompileDynamic + private List getAllInternal(List ids) { + if (!ids) return [] + + (List)hibernateTemplate.execute { Session session -> + def identityType = persistentEntity.identity.type + def identityName = persistentEntity.identity.name + List<Object> convertedIds = ids.collect { HibernateRuntimeUtils.convertValueToType((Serializable)it, identityType, conversionService) } + CriteriaBuilder cb = session.getCriteriaBuilder() + CriteriaQuery cq = cb.createQuery(persistentEntity.javaClass) + def root = cq.from(persistentEntity.javaClass) + cq.select(root).where(root.get("id").in(convertedIds)) + firePreQueryEvent(session, cq) + + List results = session.createQuery(cq).resultList + firePostQueryEvent(session, cq, results) + def idsMap = [:] + for (object in results) { + idsMap[object[identityName]] = object + } + results.clear() + for (id in ids) { + results << idsMap[id] + } + results + } + } + + protected Map<String,Object> filterQueryArgumentMap(Map<String,Object> query) { + Map<String,Object> queryArgs = new HashMap<>() + for (entry in query.entrySet()) { + if (entry.value instanceof CharSequence) { + queryArgs[entry.key] = entry.value.toString() + } + else { + queryArgs[entry.key] = entry.value + } + } + return queryArgs + } + + protected String buildOrdinalParameterQueryFromGString(GString query, List params) { + StringBuilder sqlString = new StringBuilder() + int i = 0 + Object[] values = query.values + def strings = query.getStrings() + for (str in strings) { + sqlString.append(str) + if (i < values.length) { + sqlString.append('?') + params.add(values[i++]) + } + } + return sqlString.toString() + } + + protected String buildNamedParameterQueryFromGString(GString query, Map params) { + StringBuilder sqlString = new StringBuilder() + int i = 0 + Object[] values = query.values + def strings = query.getStrings() + for (str in strings) { + sqlString.append(str) + if (i < values.length) { + String parameterName = "p$i" + sqlString.append(':').append(parameterName) + params.put(parameterName, values[i++]) + } + } + return sqlString.toString() + } + + protected List<String> removeNullNames(Map query) { + List<String> nullNames = [] + Set<String> allNames = new HashSet<>(query.keySet() as Set<String>) + for (String name in allNames) { + if (query[name] == null) { + query.remove name + nullNames << name + } + } + nullNames + } + + protected Serializable convertIdentifier(Serializable id) { + def identity = persistentEntity.identity + if(identity != null) { + ConversionService conversionService = persistentEntity.mappingContext.conversionService + if(id != null) { + Class identityType = identity.type + Class idInstanceType = id.getClass() + if(identityType.isAssignableFrom(idInstanceType)) { + return id + } + else if(conversionService.canConvert(idInstanceType, identityType)) { + try { + return (Serializable)conversionService.convert(id, identityType) + } catch (Throwable e) { + return null + } + } + else { + return null + } + } + } + return id + } + + protected void populateQueryWithNamedArguments(Query q, Map queryNamedArgs) { + if (queryNamedArgs) { + for (Map.Entry entry in queryNamedArgs.entrySet()) { + def key = entry.key + if (!(key instanceof CharSequence)) { + throw new GrailsQueryException("Named parameter's name must be String: $queryNamedArgs") + } + String stringKey = key.toString() + def value = entry.value + + if(value == null) { + q.setParameter stringKey, null + } else if (value instanceof CharSequence) { + q.setParameter stringKey, value.toString() + } else if (List.class.isAssignableFrom(value.getClass())) { + q.setParameterList stringKey, (List) value + } else if (Set.class.isAssignableFrom(value.getClass())) { + q.setParameterList stringKey, (Set) value + } else if (value.getClass().isArray()) { + q.setParameterList stringKey, (Object[]) value + } else { + q.setParameter stringKey, value + } + } + } + } + + protected Integer intValue(Map args, String key) { + def value = args.get(key) + if(value) { + return conversionService.convert(value, Integer.class) + } + return null + } + + protected void populateQueryArguments(Query q, Map args) { + Integer max = intValue(args, DynamicFinder.ARGUMENT_MAX) + args.remove(DynamicFinder.ARGUMENT_MAX) + Integer offset = intValue(args, DynamicFinder.ARGUMENT_OFFSET) + args.remove(DynamicFinder.ARGUMENT_OFFSET) + + if (max != null) { + q.maxResults = max + } + if (offset != null) { + q.firstResult = offset + } + + if (args.containsKey(DynamicFinder.ARGUMENT_CACHE)) { + q.cacheable = ClassUtils.getBooleanFromMap(DynamicFinder.ARGUMENT_CACHE, args) + } + if (args.containsKey(DynamicFinder.ARGUMENT_FETCH_SIZE)) { + Integer fetchSizeParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_FETCH_SIZE), Integer.class); + q.setFetchSize(fetchSizeParam.intValue()); + } + if (args.containsKey(DynamicFinder.ARGUMENT_TIMEOUT)) { + Integer timeoutParam = conversionService.convert(args.remove(DynamicFinder.ARGUMENT_TIMEOUT), Integer.class); + q.setTimeout(timeoutParam.intValue()); + } + if (args.containsKey(DynamicFinder.ARGUMENT_READ_ONLY)) { + q.setReadOnly((Boolean)args.remove(DynamicFinder.ARGUMENT_READ_ONLY)); + } + if (args.containsKey(DynamicFinder.ARGUMENT_FLUSH_MODE)) { + q.setHibernateFlushMode((FlushMode)args.remove(DynamicFinder.ARGUMENT_FLUSH_MODE)); + } + + args.remove(DynamicFinder.ARGUMENT_CACHE) + } + + private String normalizeMultiLineQueryString(String query) { + if (query.indexOf('\n') != -1) + return query.trim().replace('\n', ' ') + return query } @Override @@ -128,7 +843,6 @@ class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { return GormEnhancer.findStaticApi(persistentClass, name) } - @Override GrailsCriteria createCriteria() { def builder = new HibernateCriteriaBuilder(persistentClass, sessionFactory,(AbstractHibernateDatastore)datastore) @@ -143,7 +857,6 @@ class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { @Override Integer executeUpdate(CharSequence query, Map params, Map args) { - if(query instanceof GString) { params = new LinkedHashMap(params) query = buildNamedParameterQueryFromGString((GString) query, params) @@ -186,7 +899,6 @@ class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { q.timeout = sessionHolder.timeToLiveInSeconds } - params.eachWithIndex { val, int i -> if (val instanceof CharSequence) { q.setParameter i, val.toString() @@ -204,33 +916,26 @@ class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { protected <T> T withQueryEvents(Query query, Closure<T> callable) { HibernateDatastore hibernateDatastore = (HibernateDatastore)datastore - def eventPublisher = hibernateDatastore.applicationEventPublisher - def hqlQuery = new HibernateHqlQuery(new HibernateSession(hibernateDatastore, sessionFactory), persistentEntity, query) eventPublisher.publishEvent(new PreQueryEvent(hibernateDatastore, hqlQuery)) - def result = callable.call() - eventPublisher.publishEvent(new PostQueryEvent(hibernateDatastore, hqlQuery, Collections.singletonList(result))) return result } - @Override protected void firePostQueryEvent(Session session, CriteriaQuery criteria, Object result) { def hibernateQuery = new HibernateQuery(new HibernateSession((HibernateDatastore) datastore, sessionFactory), persistentEntity) def list = result instanceof List ? (List)result : Collections.singletonList(result) datastore.applicationEventPublisher.publishEvent( new PostQueryEvent(datastore, hibernateQuery, list)) } - @Override protected void firePreQueryEvent(Session session, CriteriaQuery criteria) { def hibernateSession = new HibernateSession((HibernateDatastore) datastore, sessionFactory) def hibernateQuery = new HibernateQuery(hibernateSession, persistentEntity) datastore.applicationEventPublisher.publishEvent(new PreQueryEvent(datastore, hibernateQuery)) } - @Override protected HibernateHqlQuery createHqlQuery(Session session, Query q) { HibernateSession hibernateSession = new HibernateSession((HibernateDatastore) datastore, sessionFactory) FlushMode hibernateMode = session.getHibernateFlushMode() @@ -243,7 +948,6 @@ class HibernateGormStaticApi<D> extends AbstractHibernateGormStaticApi<D> { break default: hibernateSession.setFlushMode(FlushModeType.COMMIT) - } HibernateHqlQuery query = new HibernateHqlQuery(hibernateSession, persistentEntity, q) return query diff --git a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java deleted file mode 100644 index 9d19219278..0000000000 --- a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/AbstractHibernateCriteriaBuilder.java +++ /dev/null @@ -1,1496 +0,0 @@ -package org.grails.orm.hibernate.query; - -import grails.gorm.DetachedCriteria; -import grails.gorm.MultiTenant; -import groovy.lang.Closure; -import groovy.lang.DelegatesTo; -import groovy.lang.GroovyObjectSupport; -import groovy.lang.GroovySystem; -import groovy.lang.MetaClass; -import groovy.lang.MetaMethod; -import groovy.lang.MissingMethodException; -import groovy.util.logging.Slf4j; -import jakarta.persistence.criteria.CriteriaQuery; -import jakarta.persistence.criteria.Join; -import jakarta.persistence.criteria.JoinType; -import jakarta.persistence.criteria.Root; -import jakarta.persistence.criteria.Subquery; -import jakarta.persistence.metamodel.Attribute; -import jakarta.persistence.metamodel.EntityType; -import jakarta.persistence.metamodel.Metamodel; -import org.grails.datastore.mapping.multitenancy.MultiTenancySettings; -import org.grails.datastore.mapping.query.Query; -import org.grails.datastore.mapping.query.api.BuildableCriteria; -import org.grails.datastore.mapping.query.api.Criteria; -import org.grails.datastore.mapping.query.api.QueryableCriteria; -import org.grails.datastore.mapping.reflect.NameUtils; -import org.grails.orm.hibernate.AbstractHibernateDatastore; -import org.grails.orm.hibernate.AbstractHibernateSession; -import org.hibernate.FetchMode; -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.query.criteria.HibernateCriteriaBuilder; -import org.hibernate.transform.ResultTransformer; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.core.convert.ConversionService; -import org.grails.datastore.mapping.query.api.ProjectionList; - -import java.beans.PropertyDescriptor; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -/** - * Abstract super class for sharing code between Hibernate 3 and 4 implementations of HibernateCriteriaBuilder - * - * @author Graeme Rocher - * @since 3.0.7 - */ -@Slf4j -public abstract class AbstractHibernateCriteriaBuilder extends GroovyObjectSupport implements org.grails.datastore.mapping.query.api.BuildableCriteria, org.grails.datastore.mapping.query.api.ProjectionList { - - public static final String AND = "and"; // builder - public static final String IS_NULL = "isNull"; // builder - public static final String IS_NOT_NULL = "isNotNull"; // builder - public static final String NOT = "not";// builder - public static final String OR = "or"; // builder - public static final String ID_EQUALS = "idEq"; // builder - public static final String IS_EMPTY = "isEmpty"; //builder - public static final String IS_NOT_EMPTY = "isNotEmpty"; //builder - public static final String RLIKE = "rlike";//method - public static final String BETWEEN = "between";//method - public static final String EQUALS = "eq";//method - public static final String EQUALS_PROPERTY = "eqProperty";//method - public static final String GREATER_THAN = "gt";//method - public static final String GREATER_THAN_PROPERTY = "gtProperty";//method - public static final String GREATER_THAN_OR_EQUAL = "ge";//method - public static final String GREATER_THAN_OR_EQUAL_PROPERTY = "geProperty";//method - public static final String ILIKE = "ilike";//method - public static final String IN = "in";//method - public static final String LESS_THAN = "lt"; //method - public static final String LESS_THAN_PROPERTY = "ltProperty";//method - public static final String LESS_THAN_OR_EQUAL = "le";//method - public static final String LESS_THAN_OR_EQUAL_PROPERTY = "leProperty";//method - public static final String LIKE = "like";//method - public static final String NOT_EQUAL = "ne";//method - public static final String NOT_EQUAL_PROPERTY = "neProperty";//method - public static final String SIZE_EQUALS = "sizeEq"; //method - public static final String ORDER_DESCENDING = "desc"; - public static final String ORDER_ASCENDING = "asc"; - protected static final String ROOT_DO_CALL = "doCall"; - protected static final String ROOT_CALL = "call"; - protected static final String LIST_CALL = "list"; - protected static final String LIST_DISTINCT_CALL = "listDistinct"; - protected static final String COUNT_CALL = "count"; - protected static final String GET_CALL = "get"; - protected static final String SCROLL_CALL = "scroll"; - protected static final String SET_RESULT_TRANSFORMER_CALL = "setResultTransformer"; - protected static final String PROJECTIONS = "projections"; - private static final Logger log = LoggerFactory.getLogger(AbstractHibernateCriteriaBuilder.class); - - - protected SessionFactory sessionFactory; - protected Session hibernateSession; - protected Class<?> targetClass; - protected Query.Junction junction = new Query.Conjunction(); - protected CriteriaQuery criteriaQuery; - protected MetaClass criteriaMetaClass; - protected boolean uniqueResult = false; - protected List<LogicalExpression> logicalExpressionStack = new ArrayList<LogicalExpression>(); - protected List<String> associationStack = new ArrayList<String>(); - protected boolean participate; - protected boolean scroll; - protected boolean count; - protected Query.ProjectionList projectionList = new Query.ProjectionList(); - protected List<String> aliasStack = new ArrayList<String>(); - protected Map<String, String> aliasMap = new HashMap<String, String>(); - protected static final String ALIAS = "_alias"; - protected ResultTransformer resultTransformer; - protected int aliasCount; - protected boolean paginationEnabledList = false; - protected ConversionService conversionService; - protected int defaultFlushMode; - protected AbstractHibernateDatastore datastore; - protected HibernateCriteriaBuilder cb; - protected Root root; - protected Subquery subquery; - protected HibernateQuery hibernateQuery; - private boolean shouldLock; - private boolean shouldCache; - private boolean readOnly; - private boolean distinct = false; - - @SuppressWarnings("rawtypes") - public AbstractHibernateCriteriaBuilder(Class targetClass, SessionFactory sessionFactory, AbstractHibernateDatastore datastore) { - this.targetClass = targetClass; - setDatastore(datastore); - this.sessionFactory = sessionFactory; - this.cb = sessionFactory.getCriteriaBuilder(); -// this.criteriaQuery = cb.createQuery(targetClass); -// this.root = criteriaQuery.from(targetClass); - AbstractHibernateSession session =(AbstractHibernateSession) datastore.connect(); - hibernateQuery = new HibernateQuery(session, datastore.getMappingContext().getPersistentEntity(targetClass.getTypeName())); - - } - -// @SuppressWarnings("rawtypes") -// public AbstractHibernateCriteriaBuilder(Class targetClass, SessionFactory sessionFactory, boolean uniqueResult) { -// this.targetClass = targetClass; -// this.sessionFactory = sessionFactory; -// this.uniqueResult = uniqueResult; -// this.cb = sessionFactory.getCriteriaBuilder(); -// this.criteriaQuery = cb.createQuery(targetClass); -// this.root = criteriaQuery.from(targetClass); -// } - - public void setDatastore(AbstractHibernateDatastore datastore) { - this.datastore = datastore; - if(MultiTenant.class.isAssignableFrom(targetClass) && datastore.getMultiTenancyMode() == MultiTenancySettings.MultiTenancyMode.DISCRIMINATOR ) { - datastore.enableMultiTenancyFilter(); - } - } - - public void setConversionService(ConversionService conversionService) { - this.conversionService = conversionService; - } - - /** - * A projection that selects a property name - * @param propertyName The name of the property - */ - public ProjectionList property(String propertyName) { - hibernateQuery.projections().property(propertyName); - return this; - } - - /** - * A projection that selects a distince property name - * @param propertyName The property name - */ - public ProjectionList distinct(String propertyName) { - hibernateQuery.projections().distinct(propertyName); - return this; - } - - - /** - * Adds a projection that allows the criteria to return the property average value - * - * @param propertyName The name of the property - */ - public ProjectionList avg(String propertyName) { - hibernateQuery.projections().avg(propertyName); - return this; - } - - /** - * Use a join query - * - * @param associationPath The path of the association - */ - public BuildableCriteria join(String associationPath) { - join(associationPath,JoinType.INNER); - return this; - } - - public BuildableCriteria join(String property, JoinType joinType) { - hibernateQuery.join(property,joinType); - return this; - } - - - /** - * Whether a pessimistic lock should be obtained. - * - * @param shouldLock True if it should - */ - public void lock(boolean shouldLock) { - this.shouldLock = shouldLock; - } - - /** - * Use a select query - * - * @param associationPath The path of the association - */ - public BuildableCriteria select(String associationPath) { - hibernateQuery.select(associationPath); - return this; - } - - /** - * Whether to use the query cache - * @param shouldCache True if the query should be cached - */ - public BuildableCriteria cache(boolean shouldCache) { - this.shouldCache = shouldCache; - return this; - } - - - public BuildableCriteria maxResults(int max) { - hibernateQuery.maxResults(max); - return this; - } - - /** - * Whether to check for changes on the objects loaded - * @param readOnly True to disable dirty checking - */ - public BuildableCriteria readOnly(boolean readOnly) { - this.readOnly = readOnly; - return this; - } - - /** - * Calculates the property name including any alias paths - * - * @param propertyName The property name - * @return The calculated property name - */ - protected String calculatePropertyName(String propertyName) { -// String lastAlias = getLastAlias(); -// if (lastAlias != null) { -// return lastAlias +'.'+propertyName; -// } - - return propertyName; - } - - private String getLastAlias() { - if (aliasStack.size() > 0) { - return aliasStack.get(aliasStack.size() - 1).toString(); - } - return null; - } - - public Class<?> getTargetClass() { - return targetClass; - } - - - protected abstract DetachedCriteria convertToHibernateCriteria(QueryableCriteria<?> queryableCriteria); - - /** - * Adds a projection that allows the criteria to return the property count - * - * @param propertyName The name of the property - */ - public void count(String propertyName) { - count(propertyName, null); - } - - /** - * Adds a projection that allows the criteria to return the property count - * - * @param propertyName The name of the property - * @param alias The alias to use - */ - public void count(String propertyName, String alias) { - hibernateQuery.projections().countDistinct(getFullyQualifiedColumn(propertyName, alias)); - } - - private static String getFullyQualifiedColumn(String propertyName, String alias) { - return (Objects.nonNull(alias) ? alias + "." : "") + propertyName; - } - - public ProjectionList id() { - hibernateQuery.projections().id(); - return this; - } - - public ProjectionList count() { - return rowCount(); - } - - /** - * Adds a projection that allows the criteria to return the distinct property count - * - * @param propertyName The name of the property - */ - public ProjectionList countDistinct(String propertyName) { - return countDistinct(propertyName, null); - } - - /** - * Adds a projection that allows the criteria to return the distinct property count - * - * @param propertyName The name of the property - */ - public ProjectionList groupProperty(String propertyName) { - return groupProperty(propertyName, null); - } - - public ProjectionList distinct() { - hibernateQuery.projections().distinct(); - return this; - } - - /** - * Adds a projection that allows the criteria to return the distinct property count - * - * @param propertyName The name of the property - * @param alias The alias to use - */ - public ProjectionList countDistinct(String propertyName, String alias) { - hibernateQuery.projections().countDistinct(getFullyQualifiedColumn(propertyName,alias)); - return this; - } - - - /** - * Adds a projection that allows the criteria's result to be grouped by a property - * - * @param propertyName The name of the property - * @param alias The alias to use - */ - public ProjectionList groupProperty(String propertyName, String alias) { - hibernateQuery.projections().groupProperty(getFullyQualifiedColumn(propertyName,alias)); - return this; - } - - /** - * Adds a projection that allows the criteria to retrieve a maximum property value - * - * @param propertyName The name of the property - */ - public ProjectionList max(String propertyName) { - return max(propertyName, null); - } - - /** - * Adds a projection that allows the criteria to retrieve a maximum property value - * - * @param propertyName The name of the property - * @param alias The alias to use - */ - public ProjectionList max(String propertyName, String alias) { - hibernateQuery.projections().max(getFullyQualifiedColumn(propertyName,alias)); - return this; - } - - /** - * Adds a projection that allows the criteria to retrieve a minimum property value - * - * @param propertyName The name of the property - */ - public ProjectionList min(String propertyName) { - return min(propertyName, null); - } - - /** - * Adds a projection that allows the criteria to retrieve a minimum property value - * - * @param alias The alias to use - */ - public ProjectionList min(String propertyName, String alias) { - hibernateQuery.projections().min(getFullyQualifiedColumn(propertyName,alias)); - return this; - } - - - - /** - * Adds a projection that allows the criteria to return the row count - * - */ - public ProjectionList rowCount() { - return count(); - } - - - /** - * Adds a projection that allows the criteria to retrieve the sum of the results of a property - * - * @param propertyName The name of the property - */ - public ProjectionList sum(String propertyName) { - return sum(propertyName, null); - } - - /** - * Adds a projection that allows the criteria to retrieve the sum of the results of a property - * - * @param propertyName The name of the property - * @param alias The alias to use - */ - public ProjectionList sum(String propertyName, String alias) { - hibernateQuery.projections().sum(getFullyQualifiedColumn(propertyName,alias)); - return this; - } - - /** - * Sets the fetch mode of an associated path - * - * @param associationPath The name of the associated path - * @param fetchMode The fetch mode to set - */ - public void fetchMode(String associationPath, FetchMode fetchMode) { - if (fetchMode.equals(FetchMode.SELECT)){ - hibernateQuery.detachedCriteria.select(associationPath); - } else { - hibernateQuery.detachedCriteria.join(associationPath); - } - - } - - /** - * Sets the resultTransformer. - * @param transformer The result transformer to use. - */ - public void resultTransformer(ResultTransformer transformer) { - hibernateQuery.setResultTransformer(transformer); - } - - - /** - * Creates a Criterion that compares to class properties for equality - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria eqProperty(String propertyName, String otherPropertyName) { - hibernateQuery.eqProperty(propertyName,otherPropertyName); - return this; - } - - /** - * Creates a Criterion that compares to class properties for !equality - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria neProperty(String propertyName, String otherPropertyName) { - hibernateQuery.neProperty(propertyName,otherPropertyName); - return this; - } - - /** - * Creates a Criterion that tests if the first property is greater than the second property - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria gtProperty(String propertyName, String otherPropertyName) { - hibernateQuery.gtProperty(propertyName,otherPropertyName); - return this; - } - - /** - * Creates a Criterion that tests if the first property is greater than or equal to the second property - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria geProperty(String propertyName, String otherPropertyName) { - hibernateQuery.geProperty(propertyName,otherPropertyName); - return this; - } - - /** - * Creates a Criterion that tests if the first property is less than the second property - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria ltProperty(String propertyName, String otherPropertyName) { - hibernateQuery.ltProperty(propertyName,otherPropertyName); - return this; - } - - /** - * Creates a Criterion that tests if the first property is less than or equal to the second property - * @param propertyName The first property name - * @param otherPropertyName The second property name - * @return A Criterion instance - */ - public Criteria leProperty(String propertyName, String otherPropertyName) { - hibernateQuery.leProperty(propertyName,otherPropertyName); - return this; - } - - @Override - public Criteria allEq(Map<String, Object> propertyValues) { - hibernateQuery.allEq(propertyValues); - return this; - } - - - /** - * Creates a subquery criterion that ensures the given property is equal to all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria eqAll(String propertyName, Closure<?> propertyValue) { - return eqAll(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - - /** - * Creates a subquery criterion that ensures the given property is greater than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria gtAll(String propertyName, Closure<?> propertyValue) { - return gtAll(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - /** - * Creates a subquery criterion that ensures the given property is less than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria ltAll(String propertyName, Closure<?> propertyValue) { - return ltAll(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - /** - * Creates a subquery criterion that ensures the given property is greater than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria geAll(String propertyName, Closure<?> propertyValue) { - return geAll(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - /** - * Creates a subquery criterion that ensures the given property is less than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - @SuppressWarnings({ "unchecked", "rawtypes" }) - public Criteria leAll(String propertyName, Closure<?> propertyValue) { - return leAll(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - /** - * Creates a subquery criterion that ensures the given property is equal to all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria eqAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { - hibernateQuery.eqAll(propertyName,propertyValue); - return this; - } - - /** - * Creates a subquery criterion that ensures the given property is greater than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria gtAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { - hibernateQuery.gtAll(propertyName,propertyValue); - return this; - } - - @Override - public Criteria gtSome(String propertyName, QueryableCriteria propertyValue) { - return this; - } - - @Override - public Criteria gtSome(String propertyName, Closure<?> propertyValue) { - return gtSome(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - @Override - public Criteria geSome(String propertyName, QueryableCriteria propertyValue) { - hibernateQuery.geSome(propertyName,propertyValue); - return this; - } - - @Override - public Criteria geSome(String propertyName, Closure<?> propertyValue) { - return geSome(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - @Override - public Criteria ltSome(String propertyName, QueryableCriteria propertyValue) { - hibernateQuery.ltSome(propertyName,propertyValue); - return this; - } - - @Override - public Criteria ltSome(String propertyName, Closure<?> propertyValue) { - return ltSome(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - @Override - public Criteria leSome(String propertyName, QueryableCriteria propertyValue) { - hibernateQuery.leSome(propertyName,propertyValue); - return this; - } - - @Override - public Criteria leSome(String propertyName, Closure<?> propertyValue) { - return leSome(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(propertyValue)); - } - - @Override - public Criteria in(String propertyName, QueryableCriteria<?> subquery) { - return inList(propertyName, subquery); - } - - @Override - public Criteria inList(String propertyName, QueryableCriteria<?> subquery) { - hibernateQuery.in(propertyName,subquery); - return this; - } - - @Override - public Criteria in(String propertyName, Closure<?> subquery) { - return inList(propertyName, new DetachedCriteria(targetClass).build(subquery)); - } - - @Override - public Criteria inList(String propertyName, Closure<?> subquery) { - return inList(propertyName, new DetachedCriteria(targetClass).build(subquery)); - } - - @Override - public Criteria notIn(String propertyName, QueryableCriteria<?> subquery) { - hibernateQuery.notIn(propertyName,subquery); - return this; - } - - @Override - public Criteria notIn(String propertyName, Closure<?> subquery) { - return notIn(propertyName, new grails.gorm.DetachedCriteria(targetClass).build(subquery)); - } - - /** - * Creates a subquery criterion that ensures the given property is less than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria ltAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { - hibernateQuery.ltAll(propertyName,propertyValue); - return this; - - } - - /** - * Creates a subquery criterion that ensures the given property is greater than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria geAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { - hibernateQuery.geAll(propertyName,propertyValue); - return this; - - } - - /** - * Creates a subquery criterion that ensures the given property is less than all the given returned values - * - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria leAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { - hibernateQuery.leAll(propertyName,propertyValue); - return this; - } - - /** - * Creates a "greater than" Criterion based on the specified property name and value - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria gt(String propertyName, Object propertyValue) { - hibernateQuery.gt(propertyName,propertyValue); - return this; - } - - public Criteria lte(String s, Object o) { - return le(s,o); - } - - /** - * Creates a "greater than or equal to" Criterion based on the specified property name and value - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria ge(String propertyName, Object propertyValue) { - hibernateQuery.ge(propertyName,propertyValue); - return this; - } - - /** - * Creates a "less than" Criterion based on the specified property name and value - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria lt(String propertyName, Object propertyValue) { - hibernateQuery.lt(propertyName,propertyValue); - return this; - } - - /** - * Creates a "less than or equal to" Criterion based on the specified property name and value - * @param propertyName The property name - * @param propertyValue The property value - * @return A Criterion instance - */ - public Criteria le(String propertyName, Object propertyValue) { - hibernateQuery.le(propertyName,propertyValue); - return this; - } - - public Criteria idEquals(Object o) { - return idEq(o); - } - - @Override - public Criteria exists(QueryableCriteria<?> subquery) { - hibernateQuery.exists(subquery); - return this; - } - - @Override - public Criteria notExists(QueryableCriteria<?> subquery) { - hibernateQuery.notExits(subquery); - return this; - } - - public Criteria isEmpty(String property) { - hibernateQuery.isEmpty(property); - return this; - } - - public Criteria isNotEmpty(String property) { - hibernateQuery.isNotEmpty(property); - return this; - } - - public Criteria isNull(String property) { - hibernateQuery.isNull(property); - return this; - } - - public Criteria isNotNull(String property) { - hibernateQuery.isNotNull(property); - return this; - } - - @Override - public Criteria and(Closure callable) { - hibernateQuery.and(callable); - return this; - } - - @Override - public Criteria or(Closure callable) { - hibernateQuery.or(callable); - return this; - } - - @Override - public Criteria not(Closure callable) { - hibernateQuery.not(callable); - return this; - } - - /** - * Creates an "equals" Criterion based on the specified property name and value. Case-sensitive. - * @param propertyName The property name - * @param propertyValue The property value - * - * @return A Criterion instance - */ - public Criteria eq(String propertyName, Object propertyValue) { - return eq(propertyName, propertyValue, Collections.emptyMap()); - } - - public Criteria idEq(Object o) { - return eq("id", o); - } - - /** - * Groovy moves the map to the first parameter if using the idiomatic form, e.g. - * <code>eq 'firstName', 'Fred', ignoreCase: true</code>. - * @param params optional map with customization parameters; currently only 'ignoreCase' is supported. - * @param propertyName - * @param propertyValue - * @return A Criterion instance - */ - @SuppressWarnings("rawtypes") - public Criteria eq(Map params, String propertyName, Object propertyValue) { - return eq(propertyName, propertyValue, params); - } - - /** - * Creates an "equals" Criterion based on the specified property name and value. - * Supports case-insensitive search if the <code>params</code> map contains <code>true</code> - * under the 'ignoreCase' key. - * @param propertyName The property name - * @param propertyValue The property value - * @param params optional map with customization parameters; currently only 'ignoreCase' is supported. - * - * @return A Criterion instance - */ - @SuppressWarnings("rawtypes") - public Criteria eq(String propertyName, Object propertyValue, Map params) { - if (params.get("ignoreCase") == Boolean.TRUE) { - hibernateQuery.like(propertyName, "%"+ propertyValue.toString() + "%"); - } else { - hibernateQuery.eq(propertyName,propertyValue); - } - return this; - } - - - - /** - * Creates a Criterion with from the specified property name and "like" expression - * @param propertyName The property name - * @param propertyValue The like value - * - * @return A Criterion instance - */ - public Criteria like(String propertyName, Object propertyValue) { - hibernateQuery.like(propertyName,propertyValue.toString()); - return this; - } - - - - /** - * Creates a Criterion with from the specified property name and "ilike" (a case sensitive version of "like") expression - * @param propertyName The property name - * @param propertyValue The ilike value - * - * @return A Criterion instance - */ - public Criteria ilike(String propertyName, Object propertyValue) { - hibernateQuery.ilike(propertyName,propertyValue.toString()); - return this; - } - - /** - * Applys a "in" contrain on the specified property - * @param propertyName The property name - * @param values A collection of values - * - * @return A Criterion instance - */ - @SuppressWarnings("rawtypes") - public Criteria in(String propertyName, Collection values) { - hibernateQuery.in(propertyName,values.stream().toList()); - return this; - } - - /** - * Delegates to in as in is a Groovy keyword - */ - @SuppressWarnings("rawtypes") - public Criteria inList(String propertyName, Collection values) { - return in(propertyName, values); - } - - /** - * Delegates to in as in is a Groovy keyword - */ - public Criteria inList(String propertyName, Object[] values) { - return in(propertyName, values); - } - - /** - * Applys a "in" contrain on the specified property - * @param propertyName The property name - * @param values A collection of values - * - * @return A Criterion instance - */ - public Criteria in(String propertyName, Object[] values) { - hibernateQuery.in(propertyName, List.of(values)); - return this; - } - - /** - * Orders by the specified property name (defaults to ascending) - * - * @param propertyName The property name to order by - * @return A Order instance - */ - public Criteria order(String propertyName) { - order(new Query.Order(propertyName)); - return this; - } - - - - @Override - public Criteria order(Query.Order o) { - hibernateQuery.order(o); - return this; - } - - public Criteria firstResult(int offset) { - hibernateQuery.firstResult(offset); - return this; - } - - - - - - /** - * Orders by the specified property name and direction - * - * @param propertyName The property name to order by - * @param directionString Either "asc" for ascending or "desc" for descending - * - * @return A Order instance - */ - public Criteria order(String propertyName, String directionString) { - Query.Order.Direction direction = Query.Order.Direction.DESC.name().equalsIgnoreCase(directionString) ? Query.Order.Direction.DESC : Query.Order.Direction.ASC; - hibernateQuery.order(new Query.Order(propertyName, direction)); - return this; - } - - /** - * Creates a Criterion that contrains a collection property by size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeEq(String propertyName, int size) { - hibernateQuery.sizeEq(propertyName,size); - return this; - } - - /** - * Creates a Criterion that contrains a collection property to be greater than the given size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeGt(String propertyName, int size) { - hibernateQuery.sizeGt(propertyName,size); - return this; - } - - /** - * Creates a Criterion that contrains a collection property to be greater than or equal to the given size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeGe(String propertyName, int size) { - hibernateQuery.sizeGe(propertyName,size); - return this; - } - - /** - * Creates a Criterion that contrains a collection property to be less than or equal to the given size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeLe(String propertyName, int size) { - hibernateQuery.sizeLe(propertyName,size); - return this; - } - - /** - * Creates a Criterion that contrains a collection property to be less than to the given size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeLt(String propertyName, int size) { - hibernateQuery.sizeLt(propertyName,size); - return this; - } - - /** - * Creates a Criterion with from the specified property name and "rlike" (a regular expression version of "like") expression - * - * @param propertyName The property name - * @param propertyValue The ilike value - * @return A Criterion instance - */ - public org.grails.datastore.mapping.query.api.Criteria rlike(String propertyName, Object propertyValue) { - hibernateQuery.rlike(propertyName,propertyValue.toString()); - return this; - } - - /** - * Creates a Criterion that contrains a collection property to be not equal to the given size - * - * @param propertyName The property name - * @param size The size to constrain by - * - * @return A Criterion instance - */ - public Criteria sizeNe(String propertyName, int size) { - hibernateQuery.sizeNe(propertyName,size); - return this; - } - - /** - * Creates a "not equal" Criterion based on the specified property name and value - * @param propertyName The property name - * @param propertyValue The property value - * @return The criterion object - */ - public Criteria ne(String propertyName, Object propertyValue) { - hibernateQuery.ne(propertyName,propertyValue); - return this; - } - - - /** - * Creates a "between" Criterion based on the property name and specified lo and hi values - * @param propertyName The property name - * @param lo The low value - * @param hi The high value - * @return A Criterion instance - */ - public Criteria between(String propertyName, Object lo, Object hi) { - hibernateQuery.between(propertyName,lo,hi); - return this; - } - - public Criteria gte(String s, Object o) { - return ge(s, o); - } - - - @Override - public Object list(@DelegatesTo(Criteria.class) Closure c) { - return invokeMethod(LIST_CALL, new Object[]{c}); - } - - @Override - public Object list(Map params, @DelegatesTo(Criteria.class) Closure c) { - return invokeMethod(LIST_CALL, new Object[]{params, c}); - } - - @Override - public Object listDistinct(@DelegatesTo(Criteria.class) Closure c) { - return invokeMethod(LIST_DISTINCT_CALL, new Object[]{c}); - } - - @Override - public Object get(@DelegatesTo(Criteria.class) Closure c) { - return invokeMethod(GET_CALL, new Object[]{c}); - } - - @Override - public Object scroll(@DelegatesTo(Criteria.class) Closure c) { - return invokeMethod(SCROLL_CALL, new Object[]{c}); - } - - public JoinType convertFromInt(Integer from) { - return switch (from) { - case 1 -> JoinType.LEFT; - case 2 -> JoinType.RIGHT; - default -> JoinType.INNER; - }; - } - - @SuppressWarnings("rawtypes") - @Override - public Object invokeMethod(String name, Object obj) { - Object[] args = obj.getClass().isArray() ? (Object[])obj : new Object[]{obj}; - - if (paginationEnabledList && SET_RESULT_TRANSFORMER_CALL.equals(name) && args.length == 1 && - args[0] instanceof ResultTransformer) { - hibernateQuery.setResultTransformer((ResultTransformer) args[0]); - return null; - } - - if (isCriteriaConstructionMethod(name, args)) { -// if (criteria != null) { -// throwRuntimeException(new IllegalArgumentException("call to [" + name + "] not supported here")); -// } - - if (name.equals(GET_CALL)) { - uniqueResult = true; - } - else if (name.equals(SCROLL_CALL)) { - scroll = true; - } - else if (name.equals(COUNT_CALL)) { - count = true; - } - else if (name.equals(LIST_DISTINCT_CALL)) { - distinct = true; - } - - - // Check for pagination params - if (name.equals(LIST_CALL) && args.length == 2) { - paginationEnabledList = true; - invokeClosureNode(args[1]); - } - else { - invokeClosureNode(args[0]); - } - - Object result; - if (!uniqueResult) { - if (distinct) { - hibernateQuery.distinct(); - result = hibernateQuery.list(); - } - -// else if (scroll) { -// result = hibernateQuery.scroll(); -// } - else if (count) { - hibernateQuery.projections().count(); - result = hibernateQuery.singleResult(); - } - else if (paginationEnabledList) { - Map argMap = (Map)args[0]; - // With the new query generator only the name of the field in the relation is allowed - // @see HibernateQuerySpec.joinWithProjection() for a clear example - final String sortField = (String) argMap.get(HibernateQueryConstants.ARGUMENT_SORT); - if (sortField != null) { - boolean ignoreCase = true; - Object caseArg = argMap.get(HibernateQueryConstants.ARGUMENT_IGNORE_CASE); - if (caseArg instanceof Boolean) { - ignoreCase = (Boolean) caseArg; - } - final String orderParam = (String) argMap.get(HibernateQueryConstants.ARGUMENT_ORDER); - final Query.Order.Direction direction = Query.Order.Direction.DESC.name().equalsIgnoreCase(orderParam) ? Query.Order.Direction.DESC : Query.Order.Direction.ASC; - //The default for Query.Order.ignoreCase is false and can't be set to false - Query.Order order ; - if (ignoreCase) { - order = new Query.Order(sortField, direction); - order.ignoreCase(); - } else { - order = new Query.Order(sortField, direction); - } - hibernateQuery.order(order); - } - result = hibernateQuery.list(); - } - else { - result = hibernateQuery.list(); - } - } - else { - result = hibernateQuery.singleResult(); - } - if (!participate) { - closeSession(); - } - return result; - } - - if (criteriaQuery == null) createCriteriaInstance(); - - MetaMethod metaMethod = getMetaClass().getMetaMethod(name, args); - if (metaMethod != null) { - return metaMethod.invoke(this, args); - } - - MetaClass metaClass = GroovySystem.getMetaClassRegistry().getMetaClass(targetClass); - metaMethod = metaClass.getMetaMethod(name, args); - if (metaMethod != null) { - return metaMethod.invoke(criteriaQuery, args); - } - metaMethod = metaClass.getMetaMethod(NameUtils.getSetterName(name), args); - if (metaMethod != null) { - return metaMethod.invoke(criteriaQuery, args); - } - - if (isAssociationQueryMethod(args) || isAssociationQueryWithJoinSpecificationMethod(args)) { -// if (1 == 1) { -// throw new RuntimeException("This branch needs to be filled out"); -// } - final boolean hasMoreThanOneArg = args.length > 1; - Closure callable = hasMoreThanOneArg ? (Closure) args[1] : (Closure) args[0]; - JoinType joinType = hasMoreThanOneArg ? convertFromInt((Integer)args[0]) : convertFromInt(0); - - if (name.equals(AND)) { - hibernateQuery.and(callable); - - return name; - } - - if (name.equals(OR) ) { - hibernateQuery.or(callable); - - return name; - } - - if ( name.equals(NOT)) { - hibernateQuery.not(callable); - - return name; - } - - - if (name.equals(PROJECTIONS) && args.length == 1 && (args[0] instanceof Closure)) { - - invokeClosureNode(callable); - - return name; - } - - final PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(targetClass, name); - if (pd != null && pd.getReadMethod() != null) { - final Metamodel metamodel = sessionFactory.getMetamodel(); - final EntityType<?> entityType = metamodel.entity(targetClass); - final Attribute<?, ?> attribute = entityType.getAttribute(name); - - if (attribute.isAssociation()) { - Class oldTargetClass = targetClass; - targetClass = getClassForAssociationType(attribute); - if (targetClass.equals(oldTargetClass) && !hasMoreThanOneArg) { - joinType = JoinType.LEFT; // default to left join if joining on the same table - } - - final String associationPath = getAssociationPath(); - hibernateQuery.join(name,joinType); -// createAliasIfNeccessary(name, associationPath,joinType); - // the criteria within an association node are grouped with an implicit AND - hibernateQuery.in(name, new DetachedCriteria(targetClass).build(callable)); -// invokeClosureNode(callable); -// aliasStack.remove(aliasStack.size() - 1); -// if (!aliasInstanceStack.isEmpty()) { -// aliasInstanceStack.remove(aliasInstanceStack.size() - 1); -// } -// LogicalExpression logicalExpression = logicalExpressionStack.remove(logicalExpressionStack.size()-1); -// if (!logicalExpression.args.isEmpty()) { -// addToCriteria(logicalExpression.toCriterion()); -// } -// associationStack.remove(associationStack.size()-1); - targetClass = oldTargetClass; - - return name; - } -// if (attribute.getPersistentAttributeType() == Attribute.PersistentAttributeType.EMBEDDED) { -// associationStack.add(name); -// logicalExpressionStack.add(new LogicalExpression(AND)); -// Class oldTargetClass = targetClass; -// targetClass = pd.getPropertyType(); -// invokeClosureNode(callable); -// targetClass = oldTargetClass; -// LogicalExpression logicalExpression = logicalExpressionStack.remove(logicalExpressionStack.size()-1); -// if (!logicalExpression.args.isEmpty()) { -// addToCriteria(logicalExpression.toCriterion()); -// } -// associationStack.remove(associationStack.size()-1); -// return name; -// } - } - } - else if (args.length == 1 && args[0] != null) { -// if (criteriaQuery == null) { -// throwRuntimeException(new IllegalArgumentException("call to [" + name + "] not supported here")); -// } - Object value = args[0]; - Query.Criterion c = null; - if (name.equals(ID_EQUALS)) { - return eq("id", value); - } - if (name.equals(IS_NULL) || - name.equals(IS_NOT_NULL) || - name.equals(IS_EMPTY) || - name.equals(IS_NOT_EMPTY)) { - if (!(value instanceof String)) { - throwRuntimeException(new IllegalArgumentException("call to [" + name + "] with value [" + - value + "] requires a String value.")); - } - String propertyName = calculatePropertyName((String)value); - if (name.equals(IS_NULL)) { - hibernateQuery.isNull(propertyName); - } - else if (name.equals(IS_NOT_NULL)) { - hibernateQuery.isNotNull(propertyName); - } - else if (name.equals(IS_EMPTY)) { - hibernateQuery.isEmpty(propertyName); - } - else { - hibernateQuery.isNotEmpty(propertyName); - } - } - } - throw new MissingMethodException(name, getClass(), args); - } - - - protected abstract List createPagedResultList(Map args); - - - private boolean isAssociationQueryMethod(Object[] args) { - return args.length == 1 && args[0] instanceof Closure; - } - - private boolean isAssociationQueryWithJoinSpecificationMethod(Object[] args) { - return args.length == 2 && (args[0] instanceof Number) && (args[1] instanceof Closure); - } - - - private String getAssociationPath() { - StringBuilder fullPath = new StringBuilder(); - for (Object anAssociationStack : associationStack) { - String propertyName = (String) anAssociationStack; - if (fullPath.length() > 0) fullPath.append("."); - fullPath.append(propertyName); - } - return fullPath.toString(); - } - - private boolean isCriteriaConstructionMethod(String name, Object[] args) { - return (name.equals(LIST_CALL) && args.length == 2 && args[0] instanceof Map && args[1] instanceof Closure) || - (name.equals(ROOT_CALL) || - name.equals(ROOT_DO_CALL) || - name.equals(LIST_CALL) || - name.equals(LIST_DISTINCT_CALL) || - name.equals(GET_CALL) || - name.equals(COUNT_CALL) || - name.equals(SCROLL_CALL) && args.length == 1 && args[0] instanceof Closure); - } - -// public Criteria buildCriteria(Closure<?> criteriaClosure) { -// createCriteriaInstance(); -// criteriaClosure.setDelegate(this); -// criteriaClosure.call(); -// return criteria; -// } - - - protected abstract void createCriteriaInstance(); - - protected abstract void cacheCriteriaMapping(); - - - private void invokeClosureNode(Object args) { - Closure<?> callable = (Closure<?>)args; - callable.setDelegate(this); - callable.setResolveStrategy(Closure.DELEGATE_FIRST); - callable.call(); - } - - - /** - * adds and returns the given criterion to the currently active criteria set. - * this might be either the root criteria or a currently open - * LogicalExpression. - */ - protected Query.Criterion addToCriteria(Query.Criterion c) { - if (false) { -// logicalExpressionStack.get(logicalExpressionStack.size() - 1).args.add(c); - } - else { - junction.add(c); - } - return c; - } - - - - /** - * Returns the criteria instance - * @return The criteria instance - */ - public CriteriaQuery getInstance() { - return criteriaQuery; - } - - /** - * Set whether a unique result should be returned - * @param uniqueResult True if a unique result should be returned - */ - public void setUniqueResult(boolean uniqueResult) { - this.uniqueResult = uniqueResult; - } - - - - protected abstract Class getClassForAssociationType(Attribute<?, ?> type); - - - /** - * instances of this class are pushed onto the logicalExpressionStack - * to represent all the unfinished "and", "or", and "not" expressions. - */ - protected class LogicalExpression { - public final Object name; - - public LogicalExpression(Object name) { - this.name = name; - } - - - - } - /** - * Throws a runtime exception where necessary to ensure the session gets closed - */ - protected void throwRuntimeException(RuntimeException t) { - closeSessionFollowingException(); - throw t; - } - - private void closeSessionFollowingException() { - closeSession(); - criteriaQuery = null; - } - - /** - * Closes the session if it is copen - */ - protected void closeSession() { - if (hibernateSession != null && hibernateSession.isOpen() && !participate) { - hibernateSession.close(); - } - } - - public int getDefaultFlushMode() { - return defaultFlushMode; - } - - public void setDefaultFlushMode(int defaultFlushMode) { - this.defaultFlushMode = defaultFlushMode; - } -}
