All Downloads are FREE. Search and download functionalities are using the official Maven repository.

grails.orm.HibernateCriteriaBuilder Maven / Gradle / Ivy

There is a newer version: 6.0.0.M1
Show newest version
/*
 * Copyright 2004-2005 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package grails.orm;

import grails.gorm.DetachedCriteria;
import grails.util.CollectionUtils;
import groovy.lang.Closure;
import groovy.lang.GroovyObjectSupport;
import groovy.lang.GroovySystem;
import groovy.lang.MetaClass;
import groovy.lang.MetaMethod;
import groovy.lang.MissingMethodException;

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 org.codehaus.groovy.grails.commons.GrailsApplication;
import org.codehaus.groovy.grails.commons.GrailsClassUtils;
import org.codehaus.groovy.grails.orm.hibernate.GrailsHibernateTemplate;
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsHibernateUtil;
import org.codehaus.groovy.grails.orm.hibernate.query.HibernateCriterionAdapter;
import org.codehaus.groovy.grails.orm.hibernate.query.HibernateProjectionAdapter;
import org.grails.datastore.mapping.query.Query;
import org.grails.datastore.mapping.query.api.QueryableCriteria;
import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.FetchMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.TypeHelper;
import org.hibernate.criterion.AggregateProjection;
import org.hibernate.criterion.CountProjection;
import org.hibernate.criterion.CriteriaSpecification;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.IdentifierProjection;
import org.hibernate.criterion.Junction;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Projection;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.PropertyProjection;
import org.hibernate.criterion.Restrictions;
import org.hibernate.criterion.SimpleExpression;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.AssociationType;
import org.hibernate.type.EmbeddedComponentType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.springframework.beans.BeanUtils;
import org.springframework.core.convert.ConversionService;
import org.springframework.orm.hibernate3.SessionHolder;
import org.springframework.transaction.support.TransactionSynchronizationManager;

/**
 * 

Wraps the Hibernate Criteria API in a builder. The builder can be retrieved through the "createCriteria()" dynamic static * method of Grails domain classes (Example in Groovy): * *

 *         def c = Account.createCriteria()
 *         def results = c {
 *             projections {
 *                 groupProperty("branch")
 *             }
 *             like("holderFirstName", "Fred%")
 *             and {
 *                 between("balance", 500, 1000)
 *                 eq("branch", "London")
 *             }
 *             maxResults(10)
 *             order("holderLastName", "desc")
 *         }
 * 
* *

The builder can also be instantiated standalone with a SessionFactory and persistent Class instance: * *

 *      new HibernateCriteriaBuilder(clazz, sessionFactory).list {
 *         eq("firstName", "Fred")
 *      }
 * 
* * @author Graeme Rocher */ public class HibernateCriteriaBuilder extends GroovyObjectSupport implements org.grails.datastore.mapping.query.api.Criteria, 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"; private static final String ROOT_DO_CALL = "doCall"; private static final String ROOT_CALL = "call"; private static final String LIST_CALL = "list"; private static final String LIST_DISTINCT_CALL = "listDistinct"; private static final String COUNT_CALL = "count"; private static final String GET_CALL = "get"; private static final String SCROLL_CALL = "scroll"; private static final String SET_RESULT_TRANSFORMER_CALL = "setResultTransformer"; private static final String PROJECTIONS = "projections"; private SessionFactory sessionFactory; private Session hibernateSession; private Class targetClass; private Criteria criteria; private MetaClass criteriaMetaClass; private boolean uniqueResult = false; private List logicalExpressionStack = new ArrayList(); private List associationStack = new ArrayList(); private boolean participate; private boolean scroll; private boolean count; private ProjectionList projectionList = Projections.projectionList(); private List aliasStack = new ArrayList(); private List aliasInstanceStack = new ArrayList(); private Map aliasMap = new HashMap(); private static final String ALIAS = "_alias"; private ResultTransformer resultTransformer; private int aliasCount; private boolean paginationEnabledList = false; private List orderEntries; private GrailsApplication grailsApplication; private ConversionService conversionService; @SuppressWarnings("rawtypes") public HibernateCriteriaBuilder(Class targetClass, SessionFactory sessionFactory) { this.targetClass = targetClass; this.sessionFactory = sessionFactory; } @SuppressWarnings("rawtypes") public HibernateCriteriaBuilder(Class targetClass, SessionFactory sessionFactory, boolean uniqueResult) { this.targetClass = targetClass; this.sessionFactory = sessionFactory; this.uniqueResult = uniqueResult; } public void setGrailsApplication(GrailsApplication grailsApplication) { this.grailsApplication = grailsApplication; } public void setConversionService(ConversionService conversionService) { this.conversionService = conversionService; } /** * Returns the criteria instance * @return The criteria instance */ public Criteria getInstance() { return criteria; } /** * 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; } /** * A projection that selects a property name * @param propertyName The name of the property */ public org.grails.datastore.mapping.query.api.ProjectionList property(String propertyName) { return property(propertyName, null); } /** * A projection that selects a property name * @param propertyName The name of the property * @param alias The alias to use */ public org.grails.datastore.mapping.query.api.ProjectionList property(String propertyName, String alias) { final PropertyProjection propertyProjection = Projections.property(calculatePropertyName(propertyName)); addProjectionToList(propertyProjection, alias); return this; } /** * Adds a projection to the projectList for the given alias * * @param propertyProjection The projection * @param alias The alias */ protected void addProjectionToList(Projection propertyProjection, String alias) { if (alias != null) { projectionList.add(propertyProjection,alias); } else { projectionList.add(propertyProjection); } } /** * Adds a sql projection to the criteria * * @param sql SQL projecting a single value * @param columnAlias column alias for the projected value * @param type the type of the projected value */ protected void sqlProjection(String sql, String columnAlias, Type type) { sqlProjection(sql, CollectionUtils.newList(columnAlias), CollectionUtils.newList(type)); } /** * Adds a sql projection to the criteria * * @param sql SQL projecting * @param columnAliases List of column aliases for the projected values * @param types List of types for the projected values */ protected void sqlProjection(String sql, List columnAliases, List types) { projectionList.add(Projections.sqlProjection(sql, columnAliases.toArray(new String[columnAliases.size()]), types.toArray(new Type[types.size()]))); } /** * Adds a sql projection to the criteria * * @param sql SQL projecting * @param groupBy group by clause * @param columnAliases List of column aliases for the projected values * @param types List of types for the projected values */ protected void sqlGroupProjection(String sql, String groupBy, List columnAliases, List types) { projectionList.add(Projections.sqlGroupProjection(sql, groupBy, columnAliases.toArray(new String[columnAliases.size()]), types.toArray(new Type[types.size()]))); } /** * A projection that selects a distince property name * @param propertyName The property name */ public org.grails.datastore.mapping.query.api.ProjectionList distinct(String propertyName) { distinct(propertyName, null); return this; } /** * A projection that selects a distince property name * @param propertyName The property name * @param alias The alias to use */ public org.grails.datastore.mapping.query.api.ProjectionList distinct(String propertyName, String alias) { final Projection proj = Projections.distinct(Projections.property(calculatePropertyName(propertyName))); addProjectionToList(proj,alias); return this; } /** * A distinct projection that takes a list * * @param propertyNames The list of distince property names */ @SuppressWarnings("rawtypes") public org.grails.datastore.mapping.query.api.ProjectionList distinct(Collection propertyNames) { return distinct(propertyNames, null); } /** * A distinct projection that takes a list * * @param propertyNames The list of distince property names * @param alias The alias to use */ @SuppressWarnings("rawtypes") public org.grails.datastore.mapping.query.api.ProjectionList distinct(Collection propertyNames, String alias) { ProjectionList list = Projections.projectionList(); for (Object o : propertyNames) { list.add(Projections.property(calculatePropertyName(o.toString()))); } final Projection proj = Projections.distinct(list); addProjectionToList(proj, alias); return this; } /** * Adds a projection that allows the criteria to return the property average value * * @param propertyName The name of the property */ public org.grails.datastore.mapping.query.api.ProjectionList avg(String propertyName) { return avg(propertyName, null); } /** * Adds a projection that allows the criteria to return the property average value * * @param propertyName The name of the property * @param alias The alias to use */ public org.grails.datastore.mapping.query.api.ProjectionList avg(String propertyName, String alias) { final AggregateProjection aggregateProjection = Projections.avg(calculatePropertyName(propertyName)); addProjectionToList(aggregateProjection, alias); return this; } /** * Use a join query * * @param associationPath The path of the association */ public void join(String associationPath) { criteria.setFetchMode(calculatePropertyName(associationPath), FetchMode.JOIN); } /** * Whether a pessimistic lock should be obtained. * * @param shouldLock True if it should */ public void lock(boolean shouldLock) { String lastAlias = getLastAlias(); if (shouldLock) { if (lastAlias != null) { criteria.setLockMode(lastAlias, LockMode.PESSIMISTIC_WRITE); } else { criteria.setLockMode(LockMode.PESSIMISTIC_WRITE); } } else { if (lastAlias != null) { criteria.setLockMode(lastAlias, LockMode.NONE); } else { criteria.setLockMode(LockMode.NONE); } } } /** * Use a select query * * @param associationPath The path of the association */ public void select(String associationPath) { criteria.setFetchMode(calculatePropertyName(associationPath), FetchMode.SELECT); } /** * Whether to use the query cache * @param shouldCache True if the query should be cached */ public void cache(boolean shouldCache) { criteria.setCacheable(shouldCache); } /** * Calculates the property name including any alias paths * * @param propertyName The property name * @return The calculated property name */ private 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; } /** * Calculates the property value, converting GStrings if necessary * * @param propertyValue The property value * @return The calculated property value */ @SuppressWarnings({ "rawtypes", "unchecked" }) private Object calculatePropertyValue(Object propertyValue) { if (propertyValue instanceof CharSequence) { return propertyValue.toString(); } if (propertyValue instanceof QueryableCriteria) { propertyValue = getHibernateDetachedCriteria((QueryableCriteria)propertyValue); } else if (propertyValue instanceof Closure) { propertyValue = getHibernateDetachedCriteria( new DetachedCriteria(targetClass).build((Closure)propertyValue)); } return propertyValue; } public static org.hibernate.criterion.DetachedCriteria getHibernateDetachedCriteria(QueryableCriteria queryableCriteria) { org.hibernate.criterion.DetachedCriteria detachedCriteria = org.hibernate.criterion.DetachedCriteria.forClass( queryableCriteria.getPersistentEntity().getJavaClass()); populateHibernateDetachedCriteria(detachedCriteria, queryableCriteria); return detachedCriteria; } private static void populateHibernateDetachedCriteria(org.hibernate.criterion.DetachedCriteria detachedCriteria, QueryableCriteria queryableCriteria) { List criteriaList = queryableCriteria.getCriteria(); for (Query.Criterion criterion : criteriaList) { Criterion hibernateCriterion = new HibernateCriterionAdapter(criterion).toHibernateCriterion(null); if (hibernateCriterion != null) { detachedCriteria.add(hibernateCriterion); } } List projections = queryableCriteria.getProjections(); ProjectionList projectionList = Projections.projectionList(); for (Query.Projection projection : projections) { Projection hibernateProjection = new HibernateProjectionAdapter(projection).toHibernateProjection(); if (hibernateProjection != null) { projectionList.add(hibernateProjection); } } detachedCriteria.setProjection(projectionList); } /** * 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) { final CountProjection proj = Projections.count(calculatePropertyName(propertyName)); addProjectionToList(proj, alias); } public org.grails.datastore.mapping.query.api.ProjectionList id() { final IdentifierProjection proj = Projections.id(); addProjectionToList(proj, null); return this; } public org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.ProjectionList countDistinct(String propertyName) { return countDistinct(propertyName, null); } public org.grails.datastore.mapping.query.api.ProjectionList 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 org.grails.datastore.mapping.query.api.ProjectionList countDistinct(String propertyName, String alias) { final CountProjection proj = Projections.countDistinct(calculatePropertyName(propertyName)); addProjectionToList(proj, 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 */ public void groupProperty(String propertyName) { groupProperty(propertyName, null); } /** * 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 void groupProperty(String propertyName, String alias) { final PropertyProjection proj = Projections.groupProperty(calculatePropertyName(propertyName)); addProjectionToList(proj, alias); } /** * Adds a projection that allows the criteria to retrieve a maximum property value * * @param propertyName The name of the property */ public org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.ProjectionList max(String propertyName, String alias) { final AggregateProjection proj = Projections.max(calculatePropertyName(propertyName)); addProjectionToList(proj, alias); return this; } /** * Adds a projection that allows the criteria to retrieve a minimum property value * * @param propertyName The name of the property */ public org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.ProjectionList min(String propertyName, String alias) { final AggregateProjection aggregateProjection = Projections.min(calculatePropertyName(propertyName)); addProjectionToList(aggregateProjection, alias); return this; } /** * Adds a projection that allows the criteria to return the row count * */ public org.grails.datastore.mapping.query.api.ProjectionList rowCount() { return rowCount(null); } /** * Adds a projection that allows the criteria to return the row count * * @param alias The alias to use */ public org.grails.datastore.mapping.query.api.ProjectionList rowCount(String alias) { final Projection proj = Projections.rowCount(); addProjectionToList(proj, alias); return this; } /** * 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 org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.ProjectionList sum(String propertyName, String alias) { final AggregateProjection proj = Projections.sum(calculatePropertyName(propertyName)); addProjectionToList(proj, 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 (criteria != null) { criteria.setFetchMode(associationPath, fetchMode); } } /** * Sets the resultTransformer. * @param transformer The result transformer to use. */ public void resultTransformer(ResultTransformer transformer) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("Call to [resultTransformer] not supported here")); } resultTransformer = transformer; } /** * Join an association, assigning an alias to the joined association. *

* Functionally equivalent to createAlias(String, String, int) using * CriteriaSpecificationINNER_JOIN for the joinType. * * @param associationPath A dot-seperated property path * @param alias The alias to assign to the joined association (for later reference). * * @return this (for method chaining) * #see {@link #createAlias(String, String, int)} * @throws HibernateException Indicates a problem creating the sub criteria */ public Criteria createAlias(String associationPath, String alias) { return criteria.createAlias(associationPath, alias); } /** * Join an association using the specified join-type, assigning an alias * to the joined association. *

* The joinType is expected to be one of CriteriaSpecification.INNER_JOIN (the default), * CriteriaSpecificationFULL_JOIN, or CriteriaSpecificationLEFT_JOIN. * * @param associationPath A dot-seperated property path * @param alias The alias to assign to the joined association (for later reference). * @param joinType The type of join to use. * * @return this (for method chaining) * @see #createAlias(String, String) * @throws HibernateException Indicates a problem creating the sub criteria */ public Criteria createAlias(String associationPath, String alias, int joinType) { return criteria.createAlias(associationPath, alias, joinType); } /** * 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 org.grails.datastore.mapping.query.api.Criteria eqProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [eqProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria neProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [neProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria gtProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [gtProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria geProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [geProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria ltProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [ltProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria leProperty(String propertyName, String otherPropertyName) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [leProperty] with propertyName [" + propertyName + "] and other property name [" + otherPropertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); otherPropertyName = calculatePropertyName(otherPropertyName); addToCriteria(Restrictions.leProperty(propertyName, otherPropertyName)); 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 org.grails.datastore.mapping.query.api.Criteria eqAll(String propertyName, Closure propertyValue) { return eqAll(propertyName, new 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 org.grails.datastore.mapping.query.api.Criteria gtAll(String propertyName, Closure propertyValue) { return gtAll(propertyName, new 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 org.grails.datastore.mapping.query.api.Criteria ltAll(String propertyName, Closure propertyValue) { return ltAll(propertyName, new 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 org.grails.datastore.mapping.query.api.Criteria geAll(String propertyName, Closure propertyValue) { return geAll(propertyName, new 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 org.grails.datastore.mapping.query.api.Criteria leAll(String propertyName, Closure propertyValue) { return leAll(propertyName, new 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 org.grails.datastore.mapping.query.api.Criteria eqAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { addToCriteria(Property.forName(propertyName).eqAll(getHibernateDetachedCriteria(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 org.grails.datastore.mapping.query.api.Criteria gtAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { addToCriteria(Property.forName(propertyName).gtAll(getHibernateDetachedCriteria(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 org.grails.datastore.mapping.query.api.Criteria ltAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { addToCriteria(Property.forName(propertyName).ltAll(getHibernateDetachedCriteria(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 org.grails.datastore.mapping.query.api.Criteria geAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { addToCriteria(Property.forName(propertyName).geAll(getHibernateDetachedCriteria(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 org.grails.datastore.mapping.query.api.Criteria leAll(String propertyName, @SuppressWarnings("rawtypes") QueryableCriteria propertyValue) { addToCriteria(Property.forName(propertyName).leAll(getHibernateDetachedCriteria(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 org.grails.datastore.mapping.query.api.Criteria gt(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [gt] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); Criterion gt; if (propertyValue instanceof org.hibernate.criterion.DetachedCriteria) { gt = Property.forName(propertyName).gt((org.hibernate.criterion.DetachedCriteria)propertyValue); } else { gt = Restrictions.gt(propertyName, propertyValue); } addToCriteria(gt); return this; } public org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.Criteria ge(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [ge] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); Criterion ge; if (propertyValue instanceof org.hibernate.criterion.DetachedCriteria) { ge = Property.forName(propertyName).ge((org.hibernate.criterion.DetachedCriteria) propertyValue); } else { ge = Restrictions.ge(propertyName, propertyValue); } addToCriteria(ge); 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 org.grails.datastore.mapping.query.api.Criteria lt(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [lt] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); Criterion lt; if (propertyValue instanceof org.hibernate.criterion.DetachedCriteria) { lt = Property.forName(propertyName).lt((org.hibernate.criterion.DetachedCriteria) propertyValue); } else { lt = Restrictions.lt(propertyName, propertyValue); } addToCriteria(lt); 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 org.grails.datastore.mapping.query.api.Criteria le(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [le] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); Criterion le; if (propertyValue instanceof org.hibernate.criterion.DetachedCriteria) { le = Property.forName(propertyName).le((org.hibernate.criterion.DetachedCriteria) propertyValue); } else { le = Restrictions.le(propertyName, propertyValue); } addToCriteria(le); return this; } public org.grails.datastore.mapping.query.api.Criteria idEquals(Object o) { return idEq(o); } public org.grails.datastore.mapping.query.api.Criteria isEmpty(String property) { String propertyName = calculatePropertyName(property); addToCriteria(Restrictions.isEmpty(propertyName)); return this; } public org.grails.datastore.mapping.query.api.Criteria isNotEmpty(String property) { String propertyName = calculatePropertyName(property); addToCriteria(Restrictions.isNotEmpty(propertyName)); return this; } public org.grails.datastore.mapping.query.api.Criteria isNull(String property) { String propertyName = calculatePropertyName(property); addToCriteria(Restrictions.isNull(propertyName)); return this; } public org.grails.datastore.mapping.query.api.Criteria isNotNull(String property) { String propertyName = calculatePropertyName(property); addToCriteria(Restrictions.isNotNull(propertyName)); 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 org.grails.datastore.mapping.query.api.Criteria eq(String propertyName, Object propertyValue) { return eq(propertyName, propertyValue, Collections.emptyMap()); } public org.grails.datastore.mapping.query.api.Criteria idEq(Object o) { return eq("id", o); } /** * Groovy moves the map to the first parameter if using the idiomatic form, e.g. * eq 'firstName', 'Fred', ignoreCase: true. * @param params optional map with customization parameters; currently only 'ignoreCase' is supported. * @param propertyName * @param propertyValue * @return A Criterion instance */ @SuppressWarnings("rawtypes") public org.grails.datastore.mapping.query.api.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 params map contains true * 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 org.grails.datastore.mapping.query.api.Criteria eq(String propertyName, Object propertyValue, Map params) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [eq] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); Criterion eq; if (propertyValue instanceof org.hibernate.criterion.DetachedCriteria) { eq = Property.forName(propertyName).eq((org.hibernate.criterion.DetachedCriteria) propertyValue); } else { eq = Restrictions.eq(propertyName, propertyValue); } if (params != null && (eq instanceof SimpleExpression)) { Object ignoreCase = params.get("ignoreCase"); if (ignoreCase instanceof Boolean && (Boolean)ignoreCase) { eq = ((SimpleExpression)eq).ignoreCase(); } } addToCriteria(eq); return this; } /** * Applies a sql restriction to the results to allow something like:

       def results = Person.withCriteria {
           sqlRestriction "char_length(first_name) <= 4"
       }
      
* * @param sqlRestriction the sql restriction * @return a Criteria instance */ public org.grails.datastore.mapping.query.api.Criteria sqlRestriction(String sqlRestriction) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sqlRestriction] with value [" + sqlRestriction + "] not allowed here.")); } return sqlRestriction(sqlRestriction, Collections.EMPTY_LIST); } /** * Applies a sql restriction to the results to allow something like:
       def results = Person.withCriteria {
           sqlRestriction "char_length(first_name) < ? AND char_length(first_name) > ?", [4, 9]
       }
      
* * @param sqlRestriction the sql restriction * @param values jdbc parameters * @return a Criteria instance */ public org.grails.datastore.mapping.query.api.Criteria sqlRestriction(String sqlRestriction, List values) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sqlRestriction] with value [" + sqlRestriction + "] not allowed here.")); } final int numberOfParameters = values.size(); final Type[] typesArray = new Type[numberOfParameters]; final Object[] valuesArray = new Object[numberOfParameters]; if (numberOfParameters > 0) { final TypeHelper typeHelper = sessionFactory.getTypeHelper(); for (int i = 0; i < typesArray.length; i++) { final Object value = values.get(i); typesArray[i] = typeHelper.basic(value.getClass()); valuesArray[i] = value; } } addToCriteria(Restrictions.sqlRestriction(sqlRestriction, valuesArray, typesArray)); 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 org.grails.datastore.mapping.query.api.Criteria like(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [like] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); addToCriteria(Restrictions.like(propertyName, propertyValue)); 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) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [rlike] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); addToCriteria(new RlikeExpression(propertyName, propertyValue)); 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 org.grails.datastore.mapping.query.api.Criteria ilike(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [ilike] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); addToCriteria(Restrictions.ilike(propertyName, propertyValue)); 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 org.grails.datastore.mapping.query.api.Criteria in(String propertyName, Collection values) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [in] with propertyName [" + propertyName + "] and values [" + values + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.in(propertyName, values == null ? Collections.EMPTY_LIST : values)); return this; } /** * Delegates to in as in is a Groovy keyword */ @SuppressWarnings("rawtypes") public org.grails.datastore.mapping.query.api.Criteria inList(String propertyName, Collection values) { return in(propertyName, values); } /** * Delegates to in as in is a Groovy keyword */ public org.grails.datastore.mapping.query.api.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 org.grails.datastore.mapping.query.api.Criteria in(String propertyName, Object[] values) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [in] with propertyName [" + propertyName + "] and values [" + values + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.in(propertyName, 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 org.grails.datastore.mapping.query.api.Criteria order(String propertyName) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("Call to [order] with propertyName [" + propertyName + "]not allowed here.")); } propertyName = calculatePropertyName(propertyName); Order o = Order.asc(propertyName); if (paginationEnabledList) { orderEntries.add(o); } else { criteria.addOrder(o); } return this; } /** * Orders by the specified property name (defaults to ascending) * * @param o The property name to order by * @return A Order instance */ public org.grails.datastore.mapping.query.api.Criteria order(Order o) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("Call to [order] not allowed here.")); } if (paginationEnabledList) { orderEntries.add(o); } else { criteria.addOrder(o); } return this; } /** * Orders by the specified property name and direction * * @param propertyName The property name to order by * @param direction Either "asc" for ascending or "desc" for descending * * @return A Order instance */ public org.grails.datastore.mapping.query.api.Criteria order(String propertyName, String direction) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("Call to [order] with propertyName [" + propertyName + "]not allowed here.")); } propertyName = calculatePropertyName(propertyName); Order o; if (direction.equalsIgnoreCase(ORDER_DESCENDING)) { o = Order.desc(propertyName); } else { o = Order.asc(propertyName); } if (paginationEnabledList) { orderEntries.add(o); } else { criteria.addOrder(o); } 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 org.grails.datastore.mapping.query.api.Criteria sizeEq(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeEq] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria sizeGt(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeGt] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria sizeGe(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeGe] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria sizeLe(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeLe] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria sizeLt(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeLt] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.sizeLt(propertyName, size)); 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 org.grails.datastore.mapping.query.api.Criteria sizeNe(String propertyName, int size) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [sizeNe] with propertyName [" + propertyName + "] and size [" + size + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.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 org.grails.datastore.mapping.query.api.Criteria ne(String propertyName, Object propertyValue) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [ne] with propertyName [" + propertyName + "] and value [" + propertyValue + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); propertyValue = calculatePropertyValue(propertyValue); addToCriteria(Restrictions.ne(propertyName, propertyValue)); return this; } public org.grails.datastore.mapping.query.api.Criteria notEqual(String propertyName, Object propertyValue) { return ne(propertyName, propertyValue); } /** * 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 org.grails.datastore.mapping.query.api.Criteria between(String propertyName, Object lo, Object hi) { if (!validateSimpleExpression()) { throwRuntimeException(new IllegalArgumentException("Call to [between] with propertyName [" + propertyName + "] not allowed here.")); } propertyName = calculatePropertyName(propertyName); addToCriteria(Restrictions.between(propertyName, lo, hi)); return this; } public org.grails.datastore.mapping.query.api.Criteria gte(String s, Object o) { return ge(s, o); } private boolean validateSimpleExpression() { return criteria != null; } @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) { resultTransformer = (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)) { resultTransformer = CriteriaSpecification.DISTINCT_ROOT_ENTITY; } createCriteriaInstance(); // Check for pagination params if (name.equals(LIST_CALL) && args.length == 2) { paginationEnabledList = true; orderEntries = new ArrayList(); invokeClosureNode(args[1]); } else { invokeClosureNode(args[0]); } if (resultTransformer != null) { criteria.setResultTransformer(resultTransformer); } Object result; if (!uniqueResult) { if (scroll) { result = criteria.scroll(); } else if (count) { criteria.setProjection(Projections.rowCount()); result = criteria.uniqueResult(); } else if (paginationEnabledList) { // Calculate how many results there are in total. This has been // moved to before the 'list()' invocation to avoid any "ORDER // BY" clause added by 'populateArgumentsForCriteria()', otherwise // an exception is thrown for non-string sort fields (GRAILS-2690). criteria.setFirstResult(0); criteria.setMaxResults(Integer.MAX_VALUE); // Restore the previous projection, add settings for the pagination parameters, // and then execute the query. boolean isProjection = (projectionList != null && projectionList.getLength() > 0); criteria.setProjection(isProjection ? projectionList : null); for (Order orderEntry : orderEntries) { criteria.addOrder(orderEntry); } if (resultTransformer == null) { // GRAILS-9644 - Use projection transformer criteria.setResultTransformer( isProjection ? CriteriaSpecification.PROJECTION : CriteriaSpecification.ROOT_ENTITY ); } else if (paginationEnabledList) { // relevant to GRAILS-5692 criteria.setResultTransformer(resultTransformer); } // GRAILS-7324 look if we already have association to sort by Map argMap = (Map)args[0]; final String sort = (String) argMap.get(GrailsHibernateUtil.ARGUMENT_SORT); if (sort != null) { boolean ignoreCase = true; Object caseArg = argMap.get(GrailsHibernateUtil.ARGUMENT_IGNORE_CASE); if (caseArg instanceof Boolean) { ignoreCase = (Boolean) caseArg; } final String orderParam = (String) argMap.get(GrailsHibernateUtil.ARGUMENT_ORDER); final String order = GrailsHibernateUtil.ORDER_DESC.equalsIgnoreCase(orderParam) ? GrailsHibernateUtil.ORDER_DESC : GrailsHibernateUtil.ORDER_ASC; int lastPropertyPos = sort.lastIndexOf('.'); String associationForOrdering = lastPropertyPos >= 0 ? sort.substring(0, lastPropertyPos) : null; if (associationForOrdering != null && aliasMap.containsKey(associationForOrdering)) { addOrder(criteria, aliasMap.get(associationForOrdering) + "." + sort.substring(lastPropertyPos + 1), order, ignoreCase); // remove sort from arguments map to exclude from default processing. @SuppressWarnings("unchecked") Map argMap2 = new HashMap(argMap); argMap2.remove(GrailsHibernateUtil.ARGUMENT_SORT); argMap = argMap2; } } GrailsHibernateUtil.populateArgumentsForCriteria(grailsApplication, targetClass, criteria, argMap, conversionService); GrailsHibernateTemplate ght = new GrailsHibernateTemplate(sessionFactory, grailsApplication); PagedResultList pagedRes = new PagedResultList(ght, criteria); result = pagedRes; } else { result = criteria.list(); } } else { result = GrailsHibernateUtil.unwrapIfProxy(criteria.uniqueResult()); } if (!participate) { hibernateSession.close(); } return result; } if (criteria == null) createCriteriaInstance(); MetaMethod metaMethod = getMetaClass().getMetaMethod(name, args); if (metaMethod != null) { return metaMethod.invoke(this, args); } metaMethod = criteriaMetaClass.getMetaMethod(name, args); if (metaMethod != null) { return metaMethod.invoke(criteria, args); } metaMethod = criteriaMetaClass.getMetaMethod(GrailsClassUtils.getSetterName(name), args); if (metaMethod != null) { return metaMethod.invoke(criteria, args); } if (isAssociationQueryMethod(args) || isAssociationQueryWithJoinSpecificationMethod(args)) { final boolean hasMoreThanOneArg = args.length > 1; Object callable = hasMoreThanOneArg ? args[1] : args[0]; int joinType = hasMoreThanOneArg ? (Integer)args[0] : CriteriaSpecification.INNER_JOIN; if (name.equals(AND) || name.equals(OR) || name.equals(NOT)) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("call to [" + name + "] not supported here")); } logicalExpressionStack.add(new LogicalExpression(name)); invokeClosureNode(callable); LogicalExpression logicalExpression = logicalExpressionStack.remove(logicalExpressionStack.size()-1); addToCriteria(logicalExpression.toCriterion()); return name; } if (name.equals(PROJECTIONS) && args.length == 1 && (args[0] instanceof Closure)) { if (criteria == null) { throwRuntimeException(new IllegalArgumentException("call to [" + name + "] not supported here")); } projectionList = Projections.projectionList(); invokeClosureNode(callable); if (projectionList != null && projectionList.getLength() > 0) { criteria.setProjection(projectionList); } return name; } final PropertyDescriptor pd = BeanUtils.getPropertyDescriptor(targetClass, name); if (pd != null && pd.getReadMethod() != null) { ClassMetadata meta = sessionFactory.getClassMetadata(targetClass); Type type = meta.getPropertyType(name); if (type.isAssociationType()) { String otherSideEntityName = ((AssociationType) type).getAssociatedEntityName((SessionFactoryImplementor) sessionFactory); Class oldTargetClass = targetClass; targetClass = sessionFactory.getClassMetadata(otherSideEntityName).getMappedClass(EntityMode.POJO); if (targetClass.equals(oldTargetClass) && !hasMoreThanOneArg) { joinType = CriteriaSpecification.LEFT_JOIN; // default to left join if joining on the same table } associationStack.add(name); final String associationPath = getAssociationPath(); createAliasIfNeccessary(name, associationPath,joinType); // the criteria within an association node are grouped with an implicit AND logicalExpressionStack.add(new LogicalExpression(AND)); 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 (type instanceof EmbeddedComponentType) { 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 (criteria == null) { throwRuntimeException(new IllegalArgumentException("call to [" + name + "] not supported here")); } Object value = args[0]; 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)) { c = Restrictions.isNull(propertyName); } else if (name.equals(IS_NOT_NULL)) { c = Restrictions.isNotNull(propertyName); } else if (name.equals(IS_EMPTY)) { c = Restrictions.isEmpty(propertyName); } else if (name.equals(IS_NOT_EMPTY)) { c = Restrictions.isNotEmpty(propertyName); } } if (c != null) { return addToCriteria(c); } } throw new MissingMethodException(name, getClass(), 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); } @SuppressWarnings("unused") private void addToCurrentOrAliasedCriteria(Criterion criterion) { if (!aliasInstanceStack.isEmpty()) { Criteria c = aliasInstanceStack.get(aliasInstanceStack.size()-1); c.add(criterion); } else { criteria.add(criterion); } } private void createAliasIfNeccessary(String associationName, String associationPath, int joinType) { String newAlias; if (aliasMap.containsKey(associationPath)) { newAlias = aliasMap.get(associationPath); } else { aliasCount++; newAlias = associationName + ALIAS + aliasCount; aliasMap.put(associationPath, newAlias); aliasInstanceStack.add(criteria.createAlias(associationPath, newAlias, joinType)); } aliasStack.add(newAlias); } 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; } private void createCriteriaInstance() { if (TransactionSynchronizationManager.hasResource(sessionFactory)) { participate = true; hibernateSession = ((SessionHolder)TransactionSynchronizationManager.getResource(sessionFactory)).getSession(); } else { hibernateSession = sessionFactory.openSession(); } criteria = hibernateSession.createCriteria(targetClass); GrailsHibernateUtil.cacheCriteriaByMapping(grailsApplication, targetClass, criteria); criteriaMetaClass = GroovySystem.getMetaClassRegistry().getMetaClass(criteria.getClass()); } private void invokeClosureNode(Object args) { Closure callable = (Closure)args; callable.setDelegate(this); callable.setResolveStrategy(Closure.DELEGATE_FIRST); callable.call(); } /** * Throws a runtime exception where necessary to ensure the session gets closed */ private void throwRuntimeException(RuntimeException t) { closeSessionFollowingException(); throw t; } private void closeSessionFollowingException() { if (hibernateSession != null && hibernateSession.isOpen() && !participate) { hibernateSession.close(); } criteria = null; } /** * adds and returns the given criterion to the currently active criteria set. * this might be either the root criteria or a currently open * LogicalExpression. */ private Criterion addToCriteria(Criterion c) { if (!logicalExpressionStack.isEmpty()) { logicalExpressionStack.get(logicalExpressionStack.size() - 1).args.add(c); } else { criteria.add(c); } return c; } /** * instances of this class are pushed onto the logicalExpressionStack * to represent all the unfinished "and", "or", and "not" expressions. */ private class LogicalExpression { final Object name; final List args = new ArrayList(); LogicalExpression(Object name) { this.name = name; } Criterion toCriterion() { if (name.equals(NOT)) { switch (args.size()) { case 0: throwRuntimeException(new IllegalArgumentException("Logical expression [not] must contain at least 1 expression")); return null; case 1: return Restrictions.not(args.get(0)); default: // treat multiple sub-criteria as an implicit "OR" return Restrictions.not(buildJunction(Restrictions.disjunction(), args)); } } if (name.equals(AND)) { return buildJunction(Restrictions.conjunction(), args); } if (name.equals(OR)) { return buildJunction(Restrictions.disjunction(), args); } throwRuntimeException(new IllegalStateException("Logical expression [" + name + "] not handled!")); return null; } // add the Criterion objects in the given list to the given junction. Junction buildJunction(Junction junction, List criterions) { for (Criterion c : criterions) { junction.add(c); } return junction; } } /** * Add order directly to criteria. */ private static void addOrder(Criteria c, String sort, String order, boolean ignoreCase) { if (GrailsHibernateUtil.ORDER_DESC.equals(order)) { c.addOrder( ignoreCase ? Order.desc(sort).ignoreCase() : Order.desc(sort)); } else { c.addOrder( ignoreCase ? Order.asc(sort).ignoreCase() : Order.asc(sort) ); } } /* * Define constants which may be used inside of criteria queries * to refer to standard Hibernate Type instances. */ public static final Type BOOLEAN = StandardBasicTypes.BOOLEAN; public static final Type YES_NO = StandardBasicTypes.YES_NO; public static final Type BYTE = StandardBasicTypes.BYTE; public static final Type CHARACTER = StandardBasicTypes.CHARACTER; public static final Type SHORT = StandardBasicTypes.SHORT; public static final Type INTEGER = StandardBasicTypes.INTEGER; public static final Type LONG = StandardBasicTypes.LONG; public static final Type FLOAT = StandardBasicTypes.FLOAT; public static final Type DOUBLE = StandardBasicTypes.DOUBLE; public static final Type BIG_DECIMAL = StandardBasicTypes.BIG_DECIMAL; public static final Type BIG_INTEGER = StandardBasicTypes.BIG_INTEGER; public static final Type STRING = StandardBasicTypes.STRING; public static final Type NUMERIC_BOOLEAN = StandardBasicTypes.NUMERIC_BOOLEAN; public static final Type TRUE_FALSE = StandardBasicTypes.TRUE_FALSE; public static final Type URL = StandardBasicTypes.URL; public static final Type TIME = StandardBasicTypes.TIME; public static final Type DATE = StandardBasicTypes.DATE; public static final Type TIMESTAMP = StandardBasicTypes.TIMESTAMP; public static final Type CALENDAR = StandardBasicTypes.CALENDAR; public static final Type CALENDAR_DATE = StandardBasicTypes.CALENDAR_DATE; public static final Type CLASS = StandardBasicTypes.CLASS; public static final Type LOCALE = StandardBasicTypes.LOCALE; public static final Type CURRENCY = StandardBasicTypes.CURRENCY; public static final Type TIMEZONE = StandardBasicTypes.TIMEZONE; public static final Type UUID_BINARY = StandardBasicTypes.UUID_BINARY; public static final Type UUID_CHAR = StandardBasicTypes.UUID_CHAR; public static final Type BINARY = StandardBasicTypes.BINARY; public static final Type WRAPPER_BINARY = StandardBasicTypes.WRAPPER_BINARY; public static final Type IMAGE = StandardBasicTypes.IMAGE; public static final Type BLOB = StandardBasicTypes.BLOB; public static final Type MATERIALIZED_BLOB = StandardBasicTypes.MATERIALIZED_BLOB; public static final Type WRAPPER_MATERIALIZED_BLOB = StandardBasicTypes.WRAPPER_MATERIALIZED_BLOB; public static final Type CHAR_ARRAY = StandardBasicTypes.CHAR_ARRAY; public static final Type CHARACTER_ARRAY = StandardBasicTypes.CHARACTER_ARRAY; public static final Type TEXT = StandardBasicTypes.TEXT; public static final Type CLOB = StandardBasicTypes.CLOB; public static final Type MATERIALIZED_CLOB = StandardBasicTypes.MATERIALIZED_CLOB; public static final Type WRAPPER_CHARACTERS_CLOB = StandardBasicTypes.WRAPPER_CHARACTERS_CLOB; public static final Type CHARACTERS_CLOB = StandardBasicTypes.CHARACTERS_CLOB; public static final Type SERIALIZABLE = StandardBasicTypes.SERIALIZABLE; }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy