diff --git a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateCallback.java b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateCallback.java new file mode 100644 index 00000000000..a6cca5ab8e1 --- /dev/null +++ b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateCallback.java @@ -0,0 +1,52 @@ +/* + * Copyright 2002-2014 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 org.springframework.orm.hibernate4; + +import org.hibernate.HibernateException; +import org.hibernate.Session; + +/** + * Callback interface for Hibernate code. To be used with {@link HibernateTemplate}'s + * execution methods, often as anonymous classes within a method implementation. + * A typical implementation will call {@code Session.load/find/update} to perform + * some operations on persistent objects. + * + * @author Juergen Hoeller + * @since 4.0.1 + * @see HibernateTemplate + * @see HibernateTransactionManager + */ +public interface HibernateCallback { + + /** + * Gets called by {@code HibernateTemplate.execute} with an active + * Hibernate {@code Session}. Does not need to care about activating + * or closing the {@code Session}, or handling transactions. + * + *

Allows for returning a result object created within the callback, + * i.e. a domain object or a collection of domain objects. + * A thrown custom RuntimeException is treated as an application exception: + * It gets propagated to the caller of the template. + * + * @param session active Hibernate session + * @return a result object, or {@code null} if none + * @throws HibernateException if thrown by the Hibernate API + * @see HibernateTemplate#execute + */ + T doInHibernate(Session session) throws HibernateException; + +} diff --git a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateOperations.java b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateOperations.java new file mode 100644 index 00000000000..99868012580 --- /dev/null +++ b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateOperations.java @@ -0,0 +1,798 @@ +/* + * Copyright 2002-2014 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 org.springframework.orm.hibernate4; + +import java.io.Serializable; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.hibernate.Filter; +import org.hibernate.LockMode; +import org.hibernate.ReplicationMode; +import org.hibernate.criterion.DetachedCriteria; + +import org.springframework.dao.DataAccessException; + +/** + * Interface that specifies a basic set of Hibernate operations, + * implemented by {@link HibernateTemplate}. Not often used, but a useful + * option to enhance testability, as it can easily be mocked or stubbed. + * + *

Defines {@code HibernateTemplate}'s data access methods that + * mirror various {@link org.hibernate.Session} methods. Users are + * strongly encouraged to read the Hibernate {@code Session} javadocs + * for details on the semantics of those methods. + * + * @author Juergen Hoeller + * @since 4.0.1 + * @see HibernateTemplate + * @see org.hibernate.Session + * @see HibernateTransactionManager + */ +public interface HibernateOperations { + + /** + * Execute the action specified by the given action object within a + * {@link org.hibernate.Session}. + *

Application exceptions thrown by the action object get propagated + * to the caller (can only be unchecked). Hibernate exceptions are + * transformed into appropriate DAO ones. Allows for returning a result + * object, that is a domain object or a collection of domain objects. + *

Note: Callback code is not supposed to handle transactions itself! + * Use an appropriate transaction manager like + * {@link HibernateTransactionManager}. Generally, callback code must not + * touch any {@code Session} lifecycle methods, like close, + * disconnect, or reconnect, to let the template do its work. + * @param action callback object that specifies the Hibernate action + * @return a result object returned by the action, or {@code null} + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see HibernateTransactionManager + * @see org.hibernate.Session + */ + T execute(HibernateCallback action) throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience methods for loading individual objects + //------------------------------------------------------------------------- + + /** + * Return the persistent instance of the given entity class + * with the given identifier, or {@code null} if not found. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#get(Class, java.io.Serializable)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityClass a persistent class + * @param id the identifier of the persistent instance + * @return the persistent instance, or {@code null} if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#get(Class, java.io.Serializable) + */ + T get(Class entityClass, Serializable id) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, or {@code null} if not found. + *

Obtains the specified lock mode if the instance exists. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#get(Class, java.io.Serializable, LockMode)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityClass a persistent class + * @param id the identifier of the persistent instance + * @param lockMode the lock mode to obtain + * @return the persistent instance, or {@code null} if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode) + */ + T get(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, or {@code null} if not found. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#get(String, java.io.Serializable)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityName the name of the persistent entity + * @param id the identifier of the persistent instance + * @return the persistent instance, or {@code null} if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#get(Class, java.io.Serializable) + */ + Object get(String entityName, Serializable id) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, or {@code null} if not found. + * Obtains the specified lock mode if the instance exists. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#get(String, java.io.Serializable, LockMode)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityName the name of the persistent entity + * @param id the identifier of the persistent instance + * @param lockMode the lock mode to obtain + * @return the persistent instance, or {@code null} if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode) + */ + Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, throwing an exception if not found. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#load(Class, java.io.Serializable)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityClass a persistent class + * @param id the identifier of the persistent instance + * @return the persistent instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#load(Class, java.io.Serializable) + */ + T load(Class entityClass, Serializable id) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, throwing an exception if not found. + * Obtains the specified lock mode if the instance exists. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#load(Class, java.io.Serializable, LockMode)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityClass a persistent class + * @param id the identifier of the persistent instance + * @param lockMode the lock mode to obtain + * @return the persistent instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#load(Class, java.io.Serializable) + */ + T load(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, throwing an exception if not found. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#load(String, java.io.Serializable)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityName the name of the persistent entity + * @param id the identifier of the persistent instance + * @return the persistent instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#load(Class, java.io.Serializable) + */ + Object load(String entityName, Serializable id) throws DataAccessException; + + /** + * Return the persistent instance of the given entity class + * with the given identifier, throwing an exception if not found. + *

Obtains the specified lock mode if the instance exists. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#load(String, java.io.Serializable, LockMode)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entityName the name of the persistent entity + * @param id the identifier of the persistent instance + * @param lockMode the lock mode to obtain + * @return the persistent instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#load(Class, java.io.Serializable) + */ + Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; + + /** + * Return all persistent instances of the given entity class. + * Note: Use queries or criteria for retrieving a specific subset. + * @param entityClass a persistent class + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException if there is a Hibernate error + * @see org.hibernate.Session#createCriteria + */ + List loadAll(Class entityClass) throws DataAccessException; + + /** + * Load the persistent instance with the given identifier + * into the given object, throwing an exception if not found. + *

This method is a thin wrapper around + * {@link org.hibernate.Session#load(Object, java.io.Serializable)} for convenience. + * For an explanation of the exact semantics of this method, please do refer to + * the Hibernate API documentation in the first instance. + * @param entity the object (of the target class) to load into + * @param id the identifier of the persistent instance + * @throws org.springframework.orm.ObjectRetrievalFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#load(Object, java.io.Serializable) + */ + void load(Object entity, Serializable id) throws DataAccessException; + + /** + * Re-read the state of the given persistent instance. + * @param entity the persistent instance to re-read + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#refresh(Object) + */ + void refresh(Object entity) throws DataAccessException; + + /** + * Re-read the state of the given persistent instance. + * Obtains the specified lock mode for the instance. + * @param entity the persistent instance to re-read + * @param lockMode the lock mode to obtain + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#refresh(Object, org.hibernate.LockMode) + */ + void refresh(Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Check whether the given object is in the Session cache. + * @param entity the persistence instance to check + * @return whether the given object is in the Session cache + * @throws org.springframework.dao.DataAccessException if there is a Hibernate error + * @see org.hibernate.Session#contains + */ + boolean contains(Object entity) throws DataAccessException; + + /** + * Remove the given object from the {@link org.hibernate.Session} cache. + * @param entity the persistent instance to evict + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#evict + */ + void evict(Object entity) throws DataAccessException; + + /** + * Force initialization of a Hibernate proxy or persistent collection. + * @param proxy a proxy for a persistent object or a persistent collection + * @throws DataAccessException if we can't initialize the proxy, for example + * because it is not associated with an active Session + * @see org.hibernate.Hibernate#initialize + */ + void initialize(Object proxy) throws DataAccessException; + + /** + * Return an enabled Hibernate {@link Filter} for the given filter name. + * The returned {@code Filter} instance can be used to set filter parameters. + * @param filterName the name of the filter + * @return the enabled Hibernate {@code Filter} (either already + * enabled or enabled on the fly by this operation) + * @throws IllegalStateException if we are not running within a + * transactional Session (in which case this operation does not make sense) + */ + Filter enableFilter(String filterName) throws IllegalStateException; + + + //------------------------------------------------------------------------- + // Convenience methods for storing individual objects + //------------------------------------------------------------------------- + + /** + * Obtain the specified lock level upon the given object, implicitly + * checking whether the corresponding database entry still exists. + * @param entity the persistent instance to lock + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#lock(Object, org.hibernate.LockMode) + */ + void lock(Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Obtain the specified lock level upon the given object, implicitly + * checking whether the corresponding database entry still exists. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to lock + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#lock(String, Object, org.hibernate.LockMode) + */ + void lock(String entityName, Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Persist the given transient instance. + * @param entity the transient instance to persist + * @return the generated identifier + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#save(Object) + */ + Serializable save(Object entity) throws DataAccessException; + + /** + * Persist the given transient instance. + * @param entityName the name of the persistent entity + * @param entity the transient instance to persist + * @return the generated identifier + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#save(String, Object) + */ + Serializable save(String entityName, Object entity) throws DataAccessException; + + /** + * Update the given persistent instance, + * associating it with the current Hibernate {@link org.hibernate.Session}. + * @param entity the persistent instance to update + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#update(Object) + */ + void update(Object entity) throws DataAccessException; + + /** + * Update the given persistent instance, + * associating it with the current Hibernate {@link org.hibernate.Session}. + *

Obtains the specified lock mode if the instance exists, implicitly + * checking whether the corresponding database entry still exists. + * @param entity the persistent instance to update + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#update(Object) + */ + void update(Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Update the given persistent instance, + * associating it with the current Hibernate {@link org.hibernate.Session}. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to update + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#update(String, Object) + */ + void update(String entityName, Object entity) throws DataAccessException; + + /** + * Update the given persistent instance, + * associating it with the current Hibernate {@link org.hibernate.Session}. + *

Obtains the specified lock mode if the instance exists, implicitly + * checking whether the corresponding database entry still exists. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to update + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#update(String, Object) + */ + void update(String entityName, Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Save or update the given persistent instance, + * according to its id (matching the configured "unsaved-value"?). + * Associates the instance with the current Hibernate {@link org.hibernate.Session}. + * @param entity the persistent instance to save or update + * (to be associated with the Hibernate {@code Session}) + * @throws DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#saveOrUpdate(Object) + */ + void saveOrUpdate(Object entity) throws DataAccessException; + + /** + * Save or update the given persistent instance, + * according to its id (matching the configured "unsaved-value"?). + * Associates the instance with the current Hibernate {@code Session}. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to save or update + * (to be associated with the Hibernate {@code Session}) + * @throws DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#saveOrUpdate(String, Object) + */ + void saveOrUpdate(String entityName, Object entity) throws DataAccessException; + + /** + * Persist the state of the given detached instance according to the + * given replication mode, reusing the current identifier value. + * @param entity the persistent object to replicate + * @param replicationMode the Hibernate ReplicationMode + * @throws DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#replicate(Object, org.hibernate.ReplicationMode) + */ + void replicate(Object entity, ReplicationMode replicationMode) throws DataAccessException; + + /** + * Persist the state of the given detached instance according to the + * given replication mode, reusing the current identifier value. + * @param entityName the name of the persistent entity + * @param entity the persistent object to replicate + * @param replicationMode the Hibernate ReplicationMode + * @throws DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#replicate(String, Object, org.hibernate.ReplicationMode) + */ + void replicate(String entityName, Object entity, ReplicationMode replicationMode) throws DataAccessException; + + /** + * Persist the given transient instance. Follows JSR-220 semantics. + *

Similar to {@code save}, associating the given object + * with the current Hibernate {@link org.hibernate.Session}. + * @param entity the persistent instance to persist + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#persist(Object) + * @see #save + */ + void persist(Object entity) throws DataAccessException; + + /** + * Persist the given transient instance. Follows JSR-220 semantics. + *

Similar to {@code save}, associating the given object + * with the current Hibernate {@link org.hibernate.Session}. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to persist + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#persist(String, Object) + * @see #save + */ + void persist(String entityName, Object entity) throws DataAccessException; + + /** + * Copy the state of the given object onto the persistent object + * with the same identifier. Follows JSR-220 semantics. + *

Similar to {@code saveOrUpdate}, but never associates the given + * object with the current Hibernate Session. In case of a new entity, + * the state will be copied over as well. + *

Note that {@code merge} will not update the identifiers + * in the passed-in object graph (in contrast to TopLink)! Consider + * registering Spring's {@code IdTransferringMergeEventListener} if + * you would like to have newly assigned ids transferred to the original + * object graph too. + * @param entity the object to merge with the corresponding persistence instance + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#merge(Object) + * @see #saveOrUpdate + */ + T merge(T entity) throws DataAccessException; + + /** + * Copy the state of the given object onto the persistent object + * with the same identifier. Follows JSR-220 semantics. + *

Similar to {@code saveOrUpdate}, but never associates the given + * object with the current Hibernate {@link org.hibernate.Session}. In + * the case of a new entity, the state will be copied over as well. + *

Note that {@code merge} will not update the identifiers + * in the passed-in object graph (in contrast to TopLink)! Consider + * registering Spring's {@code IdTransferringMergeEventListener} + * if you would like to have newly assigned ids transferred to the + * original object graph too. + * @param entityName the name of the persistent entity + * @param entity the object to merge with the corresponding persistence instance + * @return the updated, registered persistent instance + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#merge(String, Object) + * @see #saveOrUpdate + */ + T merge(String entityName, T entity) throws DataAccessException; + + /** + * Delete the given persistent instance. + * @param entity the persistent instance to delete + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#delete(Object) + */ + void delete(Object entity) throws DataAccessException; + + /** + * Delete the given persistent instance. + *

Obtains the specified lock mode if the instance exists, implicitly + * checking whether the corresponding database entry still exists. + * @param entity the persistent instance to delete + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#delete(Object) + */ + void delete(Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Delete the given persistent instance. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to delete + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#delete(Object) + */ + void delete(String entityName, Object entity) throws DataAccessException; + + /** + * Delete the given persistent instance. + *

Obtains the specified lock mode if the instance exists, implicitly + * checking whether the corresponding database entry still exists. + * @param entityName the name of the persistent entity + * @param entity the persistent instance to delete + * @param lockMode the lock mode to obtain + * @throws org.springframework.orm.ObjectOptimisticLockingFailureException if not found + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#delete(Object) + */ + void delete(String entityName, Object entity, LockMode lockMode) throws DataAccessException; + + /** + * Delete all given persistent instances. + *

This can be combined with any of the find methods to delete by query + * in two lines of code. + * @param entities the persistent instances to delete + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#delete(Object) + */ + void deleteAll(Collection entities) throws DataAccessException; + + /** + * Flush all pending saves, updates and deletes to the database. + *

Only invoke this for selective eager flushing, for example when + * JDBC code needs to see certain changes within the same transaction. + * Else, it is preferable to rely on auto-flushing at transaction + * completion. + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#flush + */ + void flush() throws DataAccessException; + + /** + * Remove all objects from the {@link org.hibernate.Session} cache, and + * cancel all pending saves, updates and deletes. + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#clear + */ + void clear() throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience finder methods for HQL strings + //------------------------------------------------------------------------- + + /** + * Execute an HQL query, binding a number of values to "?" parameters + * in the query string. + * @param queryString a query expressed in Hibernate's query language + * @param values the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#createQuery + */ + List find(String queryString, Object... values) throws DataAccessException; + + /** + * Execute an HQL query, binding one value to a ":" named parameter + * in the query string. + * @param queryString a query expressed in Hibernate's query language + * @param paramName the name of the parameter + * @param value the value of the parameter + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedParam(String queryString, String paramName, Object value) + throws DataAccessException; + + /** + * Execute an HQL query, binding a number of values to ":" named + * parameters in the query string. + * @param queryString a query expressed in Hibernate's query language + * @param paramNames the names of the parameters + * @param values the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedParam(String queryString, String[] paramNames, Object[] values) + throws DataAccessException; + + /** + * Execute an HQL query, binding the properties of the given bean to + * named parameters in the query string. + * @param queryString a query expressed in Hibernate's query language + * @param valueBean the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Query#setProperties + * @see org.hibernate.Session#createQuery + */ + List findByValueBean(String queryString, Object valueBean) throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience finder methods for named queries + //------------------------------------------------------------------------- + + /** + * Execute a named query binding a number of values to "?" parameters + * in the query string. + *

A named query is defined in a Hibernate mapping file. + * @param queryName the name of a Hibernate query in a mapping file + * @param values the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedQuery(String queryName, Object... values) throws DataAccessException; + + /** + * Execute a named query, binding one value to a ":" named parameter + * in the query string. + *

A named query is defined in a Hibernate mapping file. + * @param queryName the name of a Hibernate query in a mapping file + * @param paramName the name of parameter + * @param value the value of the parameter + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value) + throws DataAccessException; + + /** + * Execute a named query, binding a number of values to ":" named + * parameters in the query string. + *

A named query is defined in a Hibernate mapping file. + * @param queryName the name of a Hibernate query in a mapping file + * @param paramNames the names of the parameters + * @param values the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values) + throws DataAccessException; + + /** + * Execute a named query, binding the properties of the given bean to + * ":" named parameters in the query string. + *

A named query is defined in a Hibernate mapping file. + * @param queryName the name of a Hibernate query in a mapping file + * @param valueBean the values of the parameters + * @return a {@link List} containing the results of the query execution + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Query#setProperties + * @see org.hibernate.Session#getNamedQuery(String) + */ + List findByNamedQueryAndValueBean(String queryName, Object valueBean) + throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience finder methods for detached criteria + //------------------------------------------------------------------------- + + /** + * Execute a query based on a given Hibernate criteria object. + * @param criteria the detached Hibernate criteria object. + * Note: Do not reuse criteria objects! They need to recreated per execution, + * due to the suboptimal design of Hibernate's criteria facility. + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session) + */ + List findByCriteria(DetachedCriteria criteria) throws DataAccessException; + + /** + * Execute a query based on the given Hibernate criteria object. + * @param criteria the detached Hibernate criteria object. + * Note: Do not reuse criteria objects! They need to recreated per execution, + * due to the suboptimal design of Hibernate's criteria facility. + * @param firstResult the index of the first result object to be retrieved + * (numbered from 0) + * @param maxResults the maximum number of result objects to retrieve + * (or <=0 for no limit) + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.DetachedCriteria#getExecutableCriteria(org.hibernate.Session) + * @see org.hibernate.Criteria#setFirstResult(int) + * @see org.hibernate.Criteria#setMaxResults(int) + */ + List findByCriteria(DetachedCriteria criteria, int firstResult, int maxResults) throws DataAccessException; + + /** + * Execute a query based on the given example entity object. + * @param exampleEntity an instance of the desired entity, + * serving as example for "query-by-example" + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.Example#create(Object) + */ + List findByExample(Object exampleEntity) throws DataAccessException; + + /** + * Execute a query based on the given example entity object. + * @param entityName the name of the persistent entity + * @param exampleEntity an instance of the desired entity, + * serving as example for "query-by-example" + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.Example#create(Object) + */ + List findByExample(String entityName, Object exampleEntity) throws DataAccessException; + + /** + * Execute a query based on a given example entity object. + * @param exampleEntity an instance of the desired entity, + * serving as example for "query-by-example" + * @param firstResult the index of the first result object to be retrieved + * (numbered from 0) + * @param maxResults the maximum number of result objects to retrieve + * (or <=0 for no limit) + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.Example#create(Object) + * @see org.hibernate.Criteria#setFirstResult(int) + * @see org.hibernate.Criteria#setMaxResults(int) + */ + List findByExample(Object exampleEntity, int firstResult, int maxResults) throws DataAccessException; + + /** + * Execute a query based on a given example entity object. + * @param entityName the name of the persistent entity + * @param exampleEntity an instance of the desired entity, + * serving as example for "query-by-example" + * @param firstResult the index of the first result object to be retrieved + * (numbered from 0) + * @param maxResults the maximum number of result objects to retrieve + * (or <=0 for no limit) + * @return a {@link List} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.criterion.Example#create(Object) + * @see org.hibernate.Criteria#setFirstResult(int) + * @see org.hibernate.Criteria#setMaxResults(int) + */ + List findByExample(String entityName, Object exampleEntity, int firstResult, int maxResults) + throws DataAccessException; + + + //------------------------------------------------------------------------- + // Convenience query methods for iteration and bulk updates/deletes + //------------------------------------------------------------------------- + + /** + * Execute a query for persistent instances, binding a number of + * values to "?" parameters in the query string. + *

Returns the results as an {@link Iterator}. Entities returned are + * initialized on demand. See the Hibernate API documentation for details. + * @param queryString a query expressed in Hibernate's query language + * @param values the values of the parameters + * @return an {@link Iterator} containing 0 or more persistent instances + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#createQuery + * @see org.hibernate.Query#iterate + */ + Iterator iterate(String queryString, Object... values) throws DataAccessException; + + /** + * Immediately close an {@link Iterator} created by any of the various + * {@code iterate(..)} operations, instead of waiting until the + * session is closed or disconnected. + * @param it the {@code Iterator} to close + * @throws DataAccessException if the {@code Iterator} could not be closed + * @see org.hibernate.Hibernate#close + */ + void closeIterator(Iterator it) throws DataAccessException; + + /** + * Update/delete all objects according to the given query, binding a number of + * values to "?" parameters in the query string. + * @param queryString an update/delete query expressed in Hibernate's query language + * @param values the values of the parameters + * @return the number of instances updated/deleted + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @see org.hibernate.Session#createQuery + * @see org.hibernate.Query#executeUpdate + */ + int bulkUpdate(String queryString, Object... values) throws DataAccessException; + +} diff --git a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateTemplate.java b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateTemplate.java new file mode 100644 index 00000000000..8018a9c4de9 --- /dev/null +++ b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/HibernateTemplate.java @@ -0,0 +1,1271 @@ +/* + * Copyright 2002-2014 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 org.springframework.orm.hibernate4; + +import java.io.Serializable; +import java.lang.reflect.InvocationHandler; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.lang.reflect.Proxy; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.Criteria; +import org.hibernate.Filter; +import org.hibernate.FlushMode; +import org.hibernate.Hibernate; +import org.hibernate.HibernateException; +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.Query; +import org.hibernate.ReplicationMode; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.criterion.DetachedCriteria; +import org.hibernate.criterion.Example; + +import org.springframework.beans.factory.InitializingBean; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.transaction.support.TransactionSynchronizationManager; +import org.springframework.util.Assert; + +/** + * Helper class that simplifies Hibernate data access code. Automatically + * converts HibernateExceptions into DataAccessExceptions, following the + * {@code org.springframework.dao} exception hierarchy. + * + *

The central method is {@code execute}, supporting Hibernate access code + * implementing the {@link HibernateCallback} interface. It provides Hibernate Session + * handling such that neither the HibernateCallback implementation nor the calling + * code needs to explicitly care about retrieving/closing Hibernate Sessions, + * or handling Session lifecycle exceptions. For typical single step actions, + * there are various convenience methods (find, load, saveOrUpdate, delete). + * + *

Can be used within a service implementation via direct instantiation + * with a SessionFactory reference, or get prepared in an application context + * and given to services as bean reference. Note: The SessionFactory should + * always be configured as bean in the application context, in the first case + * given to the service directly, in the second case to the prepared template. + * + *

NOTE: Hibernate access code can also be coded in plain Hibernate style. + * Hence, for newly started projects, consider adopting the standard Hibernate + * style of coding data access objects instead, based on + * {@link org.hibernate.SessionFactory#getCurrentSession()}. + * This HibernateTemplate primarily exists as a migration helper for Hibernate 3 + * based data access code, to benefit from bug fixes in Hibernate 4.x. + * + * @author Juergen Hoeller + * @since 4.0.1 + * @see #setSessionFactory + * @see HibernateCallback + * @see org.hibernate.Session + * @see LocalSessionFactoryBean + * @see HibernateTransactionManager + * @see org.springframework.orm.hibernate4.support.OpenSessionInViewFilter + * @see org.springframework.orm.hibernate4.support.OpenSessionInViewInterceptor + */ +public class HibernateTemplate implements HibernateOperations, InitializingBean { + + protected final Log logger = LogFactory.getLog(getClass()); + + private SessionFactory sessionFactory; + + private String[] filterNames; + + private boolean exposeNativeSession = false; + + private boolean checkWriteOperations = true; + + private boolean cacheQueries = false; + + private String queryCacheRegion; + + private int fetchSize = 0; + + private int maxResults = 0; + + + /** + * Create a new HibernateTemplate instance. + */ + public HibernateTemplate() { + } + + /** + * Create a new HibernateTemplate instance. + * @param sessionFactory the SessionFactory to create Sessions with + */ + public HibernateTemplate(SessionFactory sessionFactory) { + setSessionFactory(sessionFactory); + afterPropertiesSet(); + } + + + /** + * Set the Hibernate SessionFactory that should be used to create + * Hibernate Sessions. + */ + public void setSessionFactory(SessionFactory sessionFactory) { + this.sessionFactory = sessionFactory; + } + + /** + * Return the Hibernate SessionFactory that should be used to create + * Hibernate Sessions. + */ + public SessionFactory getSessionFactory() { + return this.sessionFactory; + } + + /** + * Set one or more names of Hibernate filters to be activated for all + * Sessions that this accessor works with. + *

Each of those filters will be enabled at the beginning of each + * operation and correspondingly disabled at the end of the operation. + * This will work for newly opened Sessions as well as for existing + * Sessions (for example, within a transaction). + * @see #enableFilters(org.hibernate.Session) + * @see org.hibernate.Session#enableFilter(String) + * @see org.springframework.orm.hibernate3.LocalSessionFactoryBean#setFilterDefinitions + */ + public void setFilterNames(String... filterNames) { + this.filterNames = filterNames; + } + + /** + * Return the names of Hibernate filters to be activated, if any. + */ + public String[] getFilterNames() { + return this.filterNames; + } + + /** + * Set whether to expose the native Hibernate Session to + * HibernateCallback code. + *

Default is "false": a Session proxy will be returned, suppressing + * {@code close} calls and automatically applying query cache + * settings and transaction timeouts. + * @see HibernateCallback + * @see org.hibernate.Session + * @see #setCacheQueries + * @see #setQueryCacheRegion + * @see #prepareQuery + * @see #prepareCriteria + */ + public void setExposeNativeSession(boolean exposeNativeSession) { + this.exposeNativeSession = exposeNativeSession; + } + + /** + * Return whether to expose the native Hibernate Session to + * HibernateCallback code, or rather a Session proxy. + */ + public boolean isExposeNativeSession() { + return this.exposeNativeSession; + } + + /** + * Set whether to check that the Hibernate Session is not in read-only mode + * in case of write operations (save/update/delete). + *

Default is "true", for fail-fast behavior when attempting write operations + * within a read-only transaction. Turn this off to allow save/update/delete + * on a Session with flush mode MANUAL. + * @see #checkWriteOperationAllowed + * @see org.springframework.transaction.TransactionDefinition#isReadOnly + */ + public void setCheckWriteOperations(boolean checkWriteOperations) { + this.checkWriteOperations = checkWriteOperations; + } + + /** + * Return whether to check that the Hibernate Session is not in read-only + * mode in case of write operations (save/update/delete). + */ + public boolean isCheckWriteOperations() { + return this.checkWriteOperations; + } + + /** + * Set whether to cache all queries executed by this template. + *

If this is "true", all Query and Criteria objects created by + * this template will be marked as cacheable (including all + * queries through find methods). + *

To specify the query region to be used for queries cached + * by this template, set the "queryCacheRegion" property. + * @see #setQueryCacheRegion + * @see org.hibernate.Query#setCacheable + * @see org.hibernate.Criteria#setCacheable + */ + public void setCacheQueries(boolean cacheQueries) { + this.cacheQueries = cacheQueries; + } + + /** + * Return whether to cache all queries executed by this template. + */ + public boolean isCacheQueries() { + return this.cacheQueries; + } + + /** + * Set the name of the cache region for queries executed by this template. + *

If this is specified, it will be applied to all Query and Criteria objects + * created by this template (including all queries through find methods). + *

The cache region will not take effect unless queries created by this + * template are configured to be cached via the "cacheQueries" property. + * @see #setCacheQueries + * @see org.hibernate.Query#setCacheRegion + * @see org.hibernate.Criteria#setCacheRegion + */ + public void setQueryCacheRegion(String queryCacheRegion) { + this.queryCacheRegion = queryCacheRegion; + } + + /** + * Return the name of the cache region for queries executed by this template. + */ + public String getQueryCacheRegion() { + return this.queryCacheRegion; + } + + /** + * Set the fetch size for this HibernateTemplate. This is important for processing + * large result sets: Setting this higher than the default value will increase + * processing speed at the cost of memory consumption; setting this lower can + * avoid transferring row data that will never be read by the application. + *

Default is 0, indicating to use the JDBC driver's default. + */ + public void setFetchSize(int fetchSize) { + this.fetchSize = fetchSize; + } + + /** + * Return the fetch size specified for this HibernateTemplate. + */ + public int getFetchSize() { + return this.fetchSize; + } + + /** + * Set the maximum number of rows for this HibernateTemplate. This is important + * for processing subsets of large result sets, avoiding to read and hold + * the entire result set in the database or in the JDBC driver if we're + * never interested in the entire result in the first place (for example, + * when performing searches that might return a large number of matches). + *

Default is 0, indicating to use the JDBC driver's default. + */ + public void setMaxResults(int maxResults) { + this.maxResults = maxResults; + } + + /** + * Return the maximum number of rows specified for this HibernateTemplate. + */ + public int getMaxResults() { + return this.maxResults; + } + + @Override + public void afterPropertiesSet() { + if (getSessionFactory() == null) { + throw new IllegalArgumentException("Property 'sessionFactory' is required"); + } + } + + + @Override + public T execute(HibernateCallback action) throws DataAccessException { + return doExecute(action, false); + } + + /** + * Execute the action specified by the given action object within a + * native {@link org.hibernate.Session}. + *

This execute variant overrides the template-wide + * {@link #isExposeNativeSession() "exposeNativeSession"} setting. + * @param action callback object that specifies the Hibernate action + * @return a result object returned by the action, or {@code null} + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + */ + public T executeWithNativeSession(HibernateCallback action) { + return doExecute(action, true); + } + + /** + * Execute the action specified by the given action object within a Session. + * @param action callback object that specifies the Hibernate action + * @param enforceNativeSession whether to enforce exposure of the native + * Hibernate Session to callback code + * @return a result object returned by the action, or {@code null} + * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + */ + protected T doExecute(HibernateCallback action, boolean enforceNativeSession) throws DataAccessException { + Assert.notNull(action, "Callback object must not be null"); + + Session session = null; + boolean isNew = false; + try { + session = getSessionFactory().getCurrentSession(); + } + catch (HibernateException ex) { + logger.debug("Could not retrieve pre-bound Hibernate session", ex); + } + if (session == null) { + session = getSessionFactory().openSession(); + session.setFlushMode(FlushMode.MANUAL); + isNew = true; + } + + try { + enableFilters(session); + Session sessionToExpose = + (enforceNativeSession || isExposeNativeSession() ? session : createSessionProxy(session)); + return action.doInHibernate(sessionToExpose); + } + catch (HibernateException ex) { + throw SessionFactoryUtils.convertHibernateAccessException(ex); + } + catch (RuntimeException ex) { + // Callback code threw application exception... + throw ex; + } + finally { + if (isNew) { + SessionFactoryUtils.closeSession(session); + } + else { + disableFilters(session); + } + } + } + + /** + * Create a close-suppressing proxy for the given Hibernate Session. + * The proxy also prepares returned Query and Criteria objects. + * @param session the Hibernate Session to create a proxy for + * @return the Session proxy + * @see org.hibernate.Session#close() + * @see #prepareQuery + * @see #prepareCriteria + */ + protected Session createSessionProxy(Session session) { + return (Session) Proxy.newProxyInstance( + session.getClass().getClassLoader(), new Class[] {Session.class}, + new CloseSuppressingInvocationHandler(session)); + } + + /** + * Enable the specified filters on the given Session. + * @param session the current Hibernate Session + * @see #setFilterNames + * @see org.hibernate.Session#enableFilter(String) + */ + protected void enableFilters(Session session) { + String[] filterNames = getFilterNames(); + if (filterNames != null) { + for (String filterName : filterNames) { + session.enableFilter(filterName); + } + } + } + + /** + * Disable the specified filters on the given Session. + * @param session the current Hibernate Session + * @see #setFilterNames + * @see org.hibernate.Session#disableFilter(String) + */ + protected void disableFilters(Session session) { + String[] filterNames = getFilterNames(); + if (filterNames != null) { + for (String filterName : filterNames) { + session.disableFilter(filterName); + } + } + } + + + //------------------------------------------------------------------------- + // Convenience methods for loading individual objects + //------------------------------------------------------------------------- + + @Override + public T get(Class entityClass, Serializable id) throws DataAccessException { + return get(entityClass, id, null); + } + + @Override + public T get(final Class entityClass, final Serializable id, final LockMode lockMode) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback() { + @Override + @SuppressWarnings({"unchecked"}) + public T doInHibernate(Session session) throws HibernateException { + if (lockMode != null) { + return (T) session.get(entityClass, id, new LockOptions(lockMode)); + } + else { + return (T) session.get(entityClass, id); + } + } + }); + } + + @Override + public Object get(String entityName, Serializable id) throws DataAccessException { + return get(entityName, id, null); + } + + @Override + public Object get(final String entityName, final Serializable id, final LockMode lockMode) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + if (lockMode != null) { + return session.get(entityName, id, new LockOptions(lockMode)); + } + else { + return session.get(entityName, id); + } + } + }); + } + + @Override + public T load(Class entityClass, Serializable id) throws DataAccessException { + return load(entityClass, id, null); + } + + @Override + public T load(final Class entityClass, final Serializable id, final LockMode lockMode) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback() { + @Override + @SuppressWarnings({"unchecked"}) + public T doInHibernate(Session session) throws HibernateException { + if (lockMode != null) { + return (T) session.load(entityClass, id, new LockOptions(lockMode)); + } + else { + return (T) session.load(entityClass, id); + } + } + }); + } + + @Override + public Object load(String entityName, Serializable id) throws DataAccessException { + return load(entityName, id, null); + } + + @Override + public Object load(final String entityName, final Serializable id, final LockMode lockMode) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + if (lockMode != null) { + return session.load(entityName, id, new LockOptions(lockMode)); + } + else { + return session.load(entityName, id); + } + } + }); + } + + @Override + public List loadAll(final Class entityClass) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Criteria criteria = session.createCriteria(entityClass); + criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY); + prepareCriteria(criteria); + return criteria.list(); + } + }); + } + + @Override + public void load(final Object entity, final Serializable id) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + session.load(entity, id); + return null; + } + }); + } + + @Override + public void refresh(final Object entity) throws DataAccessException { + refresh(entity, null); + } + + @Override + public void refresh(final Object entity, final LockMode lockMode) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + if (lockMode != null) { + session.refresh(entity, new LockOptions(lockMode)); + } + else { + session.refresh(entity); + } + return null; + } + }); + } + + @Override + public boolean contains(final Object entity) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + public Boolean doInHibernate(Session session) { + return session.contains(entity); + } + }); + } + + @Override + public void evict(final Object entity) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + session.evict(entity); + return null; + } + }); + } + + @Override + public void initialize(Object proxy) throws DataAccessException { + try { + Hibernate.initialize(proxy); + } + catch (HibernateException ex) { + throw SessionFactoryUtils.convertHibernateAccessException(ex); + } + } + + @Override + public Filter enableFilter(String filterName) throws IllegalStateException { + Session session = getSessionFactory().getCurrentSession(); + Filter filter = session.getEnabledFilter(filterName); + if (filter == null) { + filter = session.enableFilter(filterName); + } + return filter; + } + + + //------------------------------------------------------------------------- + // Convenience methods for storing individual objects + //------------------------------------------------------------------------- + + @Override + public void lock(final Object entity, final LockMode lockMode) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + session.buildLockRequest(new LockOptions(lockMode)).lock(entity); + return null; + } + }); + } + + @Override + public void lock(final String entityName, final Object entity, final LockMode lockMode) + throws DataAccessException { + + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); + return null; + } + }); + } + + @Override + public Serializable save(final Object entity) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + public Serializable doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + return session.save(entity); + } + }); + } + + @Override + public Serializable save(final String entityName, final Object entity) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + public Serializable doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + return session.save(entityName, entity); + } + }); + } + + @Override + public void update(Object entity) throws DataAccessException { + update(entity, null); + } + + @Override + public void update(final Object entity, final LockMode lockMode) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.update(entity); + if (lockMode != null) { + session.buildLockRequest(new LockOptions(lockMode)).lock(entity); + } + return null; + } + }); + } + + @Override + public void update(String entityName, Object entity) throws DataAccessException { + update(entityName, entity, null); + } + + @Override + public void update(final String entityName, final Object entity, final LockMode lockMode) + throws DataAccessException { + + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.update(entityName, entity); + if (lockMode != null) { + session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); + } + return null; + } + }); + } + + @Override + public void saveOrUpdate(final Object entity) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.saveOrUpdate(entity); + return null; + } + }); + } + + @Override + public void saveOrUpdate(final String entityName, final Object entity) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.saveOrUpdate(entityName, entity); + return null; + } + }); + } + + @Override + public void replicate(final Object entity, final ReplicationMode replicationMode) + throws DataAccessException { + + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.replicate(entity, replicationMode); + return null; + } + }); + } + + @Override + public void replicate(final String entityName, final Object entity, final ReplicationMode replicationMode) + throws DataAccessException { + + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.replicate(entityName, entity, replicationMode); + return null; + } + }); + } + + @Override + public void persist(final Object entity) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.persist(entity); + return null; + } + }); + } + + @Override + public void persist(final String entityName, final Object entity) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + session.persist(entityName, entity); + return null; + } + }); + } + + @Override + public T merge(final T entity) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + @SuppressWarnings("unchecked") + public T doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + return (T) session.merge(entity); + } + }); + } + + @Override + public T merge(final String entityName, final T entity) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + @SuppressWarnings("unchecked") + public T doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + return (T) session.merge(entityName, entity); + } + }); + } + + @Override + public void delete(Object entity) throws DataAccessException { + delete(entity, null); + } + + @Override + public void delete(final Object entity, final LockMode lockMode) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + if (lockMode != null) { + session.buildLockRequest(new LockOptions(lockMode)).lock(entity); + } + session.delete(entity); + return null; + } + }); + } + + @Override + public void delete(String entityName, Object entity) throws DataAccessException { + delete(entityName, entity, null); + } + + @Override + public void delete(final String entityName, final Object entity, final LockMode lockMode) + throws DataAccessException { + + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + if (lockMode != null) { + session.buildLockRequest(new LockOptions(lockMode)).lock(entityName, entity); + } + session.delete(entityName, entity); + return null; + } + }); + } + + @Override + public void deleteAll(final Collection entities) throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + checkWriteOperationAllowed(session); + for (Object entity : entities) { + session.delete(entity); + } + return null; + } + }); + } + + @Override + public void flush() throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) throws HibernateException { + session.flush(); + return null; + } + }); + } + + @Override + public void clear() throws DataAccessException { + executeWithNativeSession(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + session.clear(); + return null; + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience finder methods for HQL strings + //------------------------------------------------------------------------- + + @Override + public List find(final String queryString, final Object... values) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.createQuery(queryString); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + queryObject.setParameter(i, values[i]); + } + } + return queryObject.list(); + } + }); + } + + @Override + public List findByNamedParam(String queryString, String paramName, Object value) + throws DataAccessException { + + return findByNamedParam(queryString, new String[]{paramName}, new Object[]{value}); + } + + @Override + public List findByNamedParam(final String queryString, final String[] paramNames, final Object[] values) + throws DataAccessException { + + if (paramNames.length != values.length) { + throw new IllegalArgumentException("Length of paramNames array must match length of values array"); + } + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.createQuery(queryString); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + applyNamedParameterToQuery(queryObject, paramNames[i], values[i]); + } + } + return queryObject.list(); + } + }); + } + + @Override + public List findByValueBean(final String queryString, final Object valueBean) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.createQuery(queryString); + prepareQuery(queryObject); + queryObject.setProperties(valueBean); + return queryObject.list(); + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience finder methods for named queries + //------------------------------------------------------------------------- + + @Override + public List findByNamedQuery(final String queryName, final Object... values) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.getNamedQuery(queryName); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + queryObject.setParameter(i, values[i]); + } + } + return queryObject.list(); + } + }); + } + + @Override + public List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value) + throws DataAccessException { + + return findByNamedQueryAndNamedParam(queryName, new String[]{paramName}, new Object[]{value}); + } + + @Override + public List findByNamedQueryAndNamedParam( + final String queryName, final String[] paramNames, final Object[] values) + throws DataAccessException { + + if (values != null && (paramNames == null || paramNames.length != values.length)) { + throw new IllegalArgumentException("Length of paramNames array must match length of values array"); + } + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.getNamedQuery(queryName); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + applyNamedParameterToQuery(queryObject, paramNames[i], values[i]); + } + } + return queryObject.list(); + } + }); + } + + @Override + public List findByNamedQueryAndValueBean(final String queryName, final Object valueBean) + throws DataAccessException { + + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Query queryObject = session.getNamedQuery(queryName); + prepareQuery(queryObject); + queryObject.setProperties(valueBean); + return queryObject.list(); + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience finder methods for detached criteria + //------------------------------------------------------------------------- + + @Override + public List findByCriteria(DetachedCriteria criteria) throws DataAccessException { + return findByCriteria(criteria, -1, -1); + } + + @Override + public List findByCriteria(final DetachedCriteria criteria, final int firstResult, final int maxResults) + throws DataAccessException { + + Assert.notNull(criteria, "DetachedCriteria must not be null"); + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Criteria executableCriteria = criteria.getExecutableCriteria(session); + prepareCriteria(executableCriteria); + if (firstResult >= 0) { + executableCriteria.setFirstResult(firstResult); + } + if (maxResults > 0) { + executableCriteria.setMaxResults(maxResults); + } + return executableCriteria.list(); + } + }); + } + + @Override + public List findByExample(Object exampleEntity) throws DataAccessException { + return findByExample(null, exampleEntity, -1, -1); + } + + @Override + public List findByExample(String entityName, Object exampleEntity) throws DataAccessException { + return findByExample(entityName, exampleEntity, -1, -1); + } + + @Override + public List findByExample(Object exampleEntity, int firstResult, int maxResults) throws DataAccessException { + return findByExample(null, exampleEntity, firstResult, maxResults); + } + + @Override + public List findByExample( + final String entityName, final Object exampleEntity, final int firstResult, final int maxResults) + throws DataAccessException { + + Assert.notNull(exampleEntity, "Example entity must not be null"); + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public List doInHibernate(Session session) throws HibernateException { + Criteria executableCriteria = (entityName != null ? + session.createCriteria(entityName) : session.createCriteria(exampleEntity.getClass())); + executableCriteria.add(Example.create(exampleEntity)); + prepareCriteria(executableCriteria); + if (firstResult >= 0) { + executableCriteria.setFirstResult(firstResult); + } + if (maxResults > 0) { + executableCriteria.setMaxResults(maxResults); + } + return executableCriteria.list(); + } + }); + } + + + //------------------------------------------------------------------------- + // Convenience query methods for iteration and bulk updates/deletes + //------------------------------------------------------------------------- + + @Override + public Iterator iterate(final String queryString, final Object... values) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback>() { + @Override + @SuppressWarnings("unchecked") + public Iterator doInHibernate(Session session) throws HibernateException { + Query queryObject = session.createQuery(queryString); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + queryObject.setParameter(i, values[i]); + } + } + return queryObject.iterate(); + } + }); + } + + @Override + public void closeIterator(Iterator it) throws DataAccessException { + try { + Hibernate.close(it); + } + catch (HibernateException ex) { + throw SessionFactoryUtils.convertHibernateAccessException(ex); + } + } + + @Override + public int bulkUpdate(final String queryString, final Object... values) throws DataAccessException { + return executeWithNativeSession(new HibernateCallback() { + @Override + public Integer doInHibernate(Session session) throws HibernateException { + Query queryObject = session.createQuery(queryString); + prepareQuery(queryObject); + if (values != null) { + for (int i = 0; i < values.length; i++) { + queryObject.setParameter(i, values[i]); + } + } + return queryObject.executeUpdate(); + } + }); + } + + + //------------------------------------------------------------------------- + // Helper methods used by the operations above + //------------------------------------------------------------------------- + + /** + * Check whether write operations are allowed on the given Session. + *

Default implementation throws an InvalidDataAccessApiUsageException in + * case of {@code FlushMode.MANUAL}. Can be overridden in subclasses. + * @param session current Hibernate Session + * @throws InvalidDataAccessApiUsageException if write operations are not allowed + * @see #setCheckWriteOperations + * @see org.hibernate.Session#getFlushMode() + * @see org.hibernate.FlushMode#MANUAL + */ + protected void checkWriteOperationAllowed(Session session) throws InvalidDataAccessApiUsageException { + if (isCheckWriteOperations() && session.getFlushMode().lessThan(FlushMode.COMMIT)) { + throw new InvalidDataAccessApiUsageException( + "Write operations are not allowed in read-only mode (FlushMode.MANUAL): "+ + "Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition."); + } + } + + /** + * Prepare the given Query object, applying cache settings and/or + * a transaction timeout. + * @param queryObject the Query object to prepare + * @see #setCacheQueries + * @see #setQueryCacheRegion + */ + protected void prepareQuery(Query queryObject) { + if (isCacheQueries()) { + queryObject.setCacheable(true); + if (getQueryCacheRegion() != null) { + queryObject.setCacheRegion(getQueryCacheRegion()); + } + } + if (getFetchSize() > 0) { + queryObject.setFetchSize(getFetchSize()); + } + if (getMaxResults() > 0) { + queryObject.setMaxResults(getMaxResults()); + } + + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory()); + if (sessionHolder != null && sessionHolder.hasTimeout()) { + queryObject.setTimeout(sessionHolder.getTimeToLiveInSeconds()); + } + } + + /** + * Prepare the given Criteria object, applying cache settings and/or + * a transaction timeout. + * @param criteria the Criteria object to prepare + * @see #setCacheQueries + * @see #setQueryCacheRegion + */ + protected void prepareCriteria(Criteria criteria) { + if (isCacheQueries()) { + criteria.setCacheable(true); + if (getQueryCacheRegion() != null) { + criteria.setCacheRegion(getQueryCacheRegion()); + } + } + if (getFetchSize() > 0) { + criteria.setFetchSize(getFetchSize()); + } + if (getMaxResults() > 0) { + criteria.setMaxResults(getMaxResults()); + } + + SessionHolder sessionHolder = + (SessionHolder) TransactionSynchronizationManager.getResource(getSessionFactory()); + if (sessionHolder != null && sessionHolder.hasTimeout()) { + criteria.setTimeout(sessionHolder.getTimeToLiveInSeconds()); + } + } + + /** + * Apply the given name parameter to the given Query object. + * @param queryObject the Query object + * @param paramName the name of the parameter + * @param value the value of the parameter + * @throws org.hibernate.HibernateException if thrown by the Query object + */ + protected void applyNamedParameterToQuery(Query queryObject, String paramName, Object value) + throws HibernateException { + + if (value instanceof Collection) { + queryObject.setParameterList(paramName, (Collection) value); + } + else if (value instanceof Object[]) { + queryObject.setParameterList(paramName, (Object[]) value); + } + else { + queryObject.setParameter(paramName, value); + } + } + + + /** + * Invocation handler that suppresses close calls on Hibernate Sessions. + * Also prepares returned Query and Criteria objects. + * @see org.hibernate.Session#close + */ + private class CloseSuppressingInvocationHandler implements InvocationHandler { + + private final Session target; + + public CloseSuppressingInvocationHandler(Session target) { + this.target = target; + } + + @Override + public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { + // Invocation on Session interface coming in... + + if (method.getName().equals("equals")) { + // Only consider equal when proxies are identical. + return (proxy == args[0]); + } + else if (method.getName().equals("hashCode")) { + // Use hashCode of Session proxy. + return System.identityHashCode(proxy); + } + else if (method.getName().equals("close")) { + // Handle close method: suppress, not valid. + return null; + } + + // Invoke method on target Session. + try { + Object retVal = method.invoke(this.target, args); + + // If return value is a Query or Criteria, apply transaction timeout. + // Applies to createQuery, getNamedQuery, createCriteria. + if (retVal instanceof Query) { + prepareQuery(((Query) retVal)); + } + if (retVal instanceof Criteria) { + prepareCriteria(((Criteria) retVal)); + } + + return retVal; + } + catch (InvocationTargetException ex) { + throw ex.getTargetException(); + } + } + } + +} diff --git a/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/support/HibernateDaoSupport.java b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/support/HibernateDaoSupport.java new file mode 100644 index 00000000000..4d1083feba1 --- /dev/null +++ b/spring-orm-hibernate4/src/main/java/org/springframework/orm/hibernate4/support/HibernateDaoSupport.java @@ -0,0 +1,132 @@ +/* + * Copyright 2002-2014 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 org.springframework.orm.hibernate4.support; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; + +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.support.DaoSupport; +import org.springframework.orm.hibernate4.HibernateTemplate; + +/** + * Convenient super class for Hibernate-based data access objects. + * + *

Requires a {@link org.hibernate.SessionFactory} to be set, providing a + * {@link org.springframework.orm.hibernate4.HibernateTemplate} based on it to + * subclasses through the {@link #getHibernateTemplate()} method. + * Can alternatively be initialized directly with a HibernateTemplate, + * in order to reuse the latter's settings such as the SessionFactory, + * exception translator, flush mode, etc. + * + *

This class will create its own HibernateTemplate instance if a SessionFactory + * is passed in. The "allowCreate" flag on that HibernateTemplate will be "true" + * by default. A custom HibernateTemplate instance can be used through overriding + * {@link #createHibernateTemplate}. + * + *

NOTE: Hibernate access code can also be coded in plain Hibernate style. + * Hence, for newly started projects, consider adopting the standard Hibernate + * style of coding data access objects instead, based on + * {@link org.hibernate.SessionFactory#getCurrentSession()}. + * This HibernateTemplate primarily exists as a migration helper for Hibernate 3 + * based data access code, to benefit from bug fixes in Hibernate 4.x. + * + * @author Juergen Hoeller + * @since 4.0.1 + * @see #setSessionFactory + * @see #getHibernateTemplate + * @see org.springframework.orm.hibernate4.HibernateTemplate + */ +public abstract class HibernateDaoSupport extends DaoSupport { + + private HibernateTemplate hibernateTemplate; + + + /** + * Set the Hibernate SessionFactory to be used by this DAO. + * Will automatically create a HibernateTemplate for the given SessionFactory. + * @see #createHibernateTemplate + * @see #setHibernateTemplate + */ + public final void setSessionFactory(SessionFactory sessionFactory) { + if (this.hibernateTemplate == null || sessionFactory != this.hibernateTemplate.getSessionFactory()) { + this.hibernateTemplate = createHibernateTemplate(sessionFactory); + } + } + + /** + * Create a HibernateTemplate for the given SessionFactory. + * Only invoked if populating the DAO with a SessionFactory reference! + *

Can be overridden in subclasses to provide a HibernateTemplate instance + * with different configuration, or a custom HibernateTemplate subclass. + * @param sessionFactory the Hibernate SessionFactory to create a HibernateTemplate for + * @return the new HibernateTemplate instance + * @see #setSessionFactory + */ + protected HibernateTemplate createHibernateTemplate(SessionFactory sessionFactory) { + return new HibernateTemplate(sessionFactory); + } + + /** + * Return the Hibernate SessionFactory used by this DAO. + */ + public final SessionFactory getSessionFactory() { + return (this.hibernateTemplate != null ? this.hibernateTemplate.getSessionFactory() : null); + } + + /** + * Set the HibernateTemplate for this DAO explicitly, + * as an alternative to specifying a SessionFactory. + * @see #setSessionFactory + */ + public final void setHibernateTemplate(HibernateTemplate hibernateTemplate) { + this.hibernateTemplate = hibernateTemplate; + } + + /** + * Return the HibernateTemplate for this DAO, + * pre-initialized with the SessionFactory or set explicitly. + *

Note: The returned HibernateTemplate is a shared instance. + * You may introspect its configuration, but not modify the configuration + * (other than from within an {@link #initDao} implementation). + * Consider creating a custom HibernateTemplate instance via + * {@code new HibernateTemplate(getSessionFactory())}, in which case + * you're allowed to customize the settings on the resulting instance. + */ + public final HibernateTemplate getHibernateTemplate() { + return this.hibernateTemplate; + } + + @Override + protected final void checkDaoConfig() { + if (this.hibernateTemplate == null) { + throw new IllegalArgumentException("'sessionFactory' or 'hibernateTemplate' is required"); + } + } + + + /** + * Conveniently obtain the current Hibernate Session. + * @return the Hibernate Session + * @throws DataAccessResourceFailureException if the Session couldn't be created + * @see org.hibernate.SessionFactory#getCurrentSession() + */ + protected final Session currentSession() throws DataAccessResourceFailureException { + return getSessionFactory().getCurrentSession(); + } + +} diff --git a/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTemplateTests.java b/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTemplateTests.java new file mode 100644 index 00000000000..47c91bafe22 --- /dev/null +++ b/spring-orm-hibernate4/src/test/java/org/springframework/orm/hibernate4/HibernateTemplateTests.java @@ -0,0 +1,1188 @@ +/* + * Copyright 2002-2014 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 org.springframework.orm.hibernate4; + +import java.lang.reflect.Proxy; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +import org.hibernate.Criteria; +import org.hibernate.Filter; +import org.hibernate.FlushMode; +import org.hibernate.HibernateException; +import org.hibernate.JDBCException; +import org.hibernate.NonUniqueResultException; +import org.hibernate.ObjectDeletedException; +import org.hibernate.ObjectNotFoundException; +import org.hibernate.PersistentObjectException; +import org.hibernate.PropertyValueException; +import org.hibernate.Query; +import org.hibernate.QueryException; +import org.hibernate.ReplicationMode; +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.StaleObjectStateException; +import org.hibernate.StaleStateException; +import org.hibernate.TransientObjectException; +import org.hibernate.UnresolvableObjectException; +import org.hibernate.WrongClassException; +import org.hibernate.exception.ConstraintViolationException; +import org.hibernate.exception.DataException; +import org.hibernate.exception.JDBCConnectionException; +import org.hibernate.exception.LockAcquisitionException; +import org.hibernate.exception.SQLGrammarException; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InOrder; + +import org.springframework.dao.CannotAcquireLockException; +import org.springframework.dao.DataAccessResourceFailureException; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.dao.IncorrectResultSizeDataAccessException; +import org.springframework.dao.InvalidDataAccessApiUsageException; +import org.springframework.dao.InvalidDataAccessResourceUsageException; +import org.springframework.tests.sample.beans.TestBean; +import org.springframework.transaction.support.TransactionSynchronizationManager; + +import static org.junit.Assert.*; +import static org.mockito.BDDMockito.*; + +/** + * @author Juergen Hoeller + * @since 4.0.1 + */ +public class HibernateTemplateTests { + + private SessionFactory sessionFactory; + private Session session; + private HibernateTemplate hibernateTemplate; + + @Before + public void setUp() { + this.sessionFactory = mock(SessionFactory.class); + this.session = mock(Session.class); + this.hibernateTemplate = new HibernateTemplate(sessionFactory); + given(sessionFactory.getCurrentSession()).willReturn(session); + } + + @After + public void tearDown() { + assertTrue(TransactionSynchronizationManager.getResourceMap().isEmpty()); + assertFalse(TransactionSynchronizationManager.isSynchronizationActive()); + } + + @Test + public void testExecuteWithNewSession() { + given(sessionFactory.getCurrentSession()).willThrow(new HibernateException("no current session")); + given(sessionFactory.openSession()).willReturn(session); + + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + verify(session).close(); + } + + @Test + public void testExecuteWithNewSessionAndFilter() { + given(sessionFactory.getCurrentSession()).willThrow(new HibernateException("no current session")); + given(sessionFactory.openSession()).willReturn(session); + hibernateTemplate.setFilterNames("myFilter"); + + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + verify(session).enableFilter("myFilter"); + verify(session).close(); + } + + @Test + public void testExecuteWithNewSessionAndFilters() { + given(sessionFactory.getCurrentSession()).willThrow(new HibernateException("no current session")); + given(sessionFactory.openSession()).willReturn(session); + hibernateTemplate.setFilterNames("myFilter", "yourFilter"); + + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + InOrder ordered = inOrder(session); + ordered.verify(session).enableFilter("myFilter"); + ordered.verify(session).enableFilter("yourFilter"); + ordered.verify(session).close(); + } + + @Test + public void testExecuteWithThreadBound() { + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + } + + @Test + public void testExecuteWithThreadBoundAndFilter() { + hibernateTemplate.setFilterNames("myFilter"); + + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + + InOrder ordered = inOrder(session); + ordered.verify(session).enableFilter("myFilter"); + ordered.verify(session).disableFilter("myFilter"); + } + + @Test + public void testExecuteWithThreadBoundAndFilters() { + hibernateTemplate.setFilterNames("myFilter", "yourFilter"); + + final List l = new ArrayList(); + l.add("test"); + List result = hibernateTemplate.execute(new HibernateCallback() { + @Override + public List doInHibernate(Session session) { + return l; + } + }); + assertTrue("Correct result list", result == l); + + InOrder ordered = inOrder(session); + ordered.verify(session).enableFilter("myFilter"); + ordered.verify(session).enableFilter("yourFilter"); + ordered.verify(session).disableFilter("myFilter"); + ordered.verify(session).disableFilter("yourFilter"); + } + + @Test + public void testExecuteWithThreadBoundAndParameterizedFilter() { + Filter filter = mock(Filter.class); + given(session.enableFilter("myFilter")).willReturn(filter); + hibernateTemplate.setFilterNames("myFilter"); + + final List l = new ArrayList(); + l.add("test"); + Filter f = hibernateTemplate.enableFilter("myFilter"); + assertTrue("Correct filter", f == filter); + + InOrder ordered = inOrder(session); + ordered.verify(session).getEnabledFilter("myFilter"); + ordered.verify(session).enableFilter("myFilter"); + } + + @Test + public void testExecuteWithThreadBoundAndParameterizedExistingFilter() { + Filter filter = mock(Filter.class); + given(session.enableFilter("myFilter")).willReturn(filter); + hibernateTemplate.setFilterNames("myFilter"); + + final List l = new ArrayList(); + l.add("test"); + Filter f = hibernateTemplate.enableFilter("myFilter"); + assertTrue("Correct filter", f == filter); + + verify(session).getEnabledFilter("myFilter"); + } + + @Test + public void testExecuteWithCacheQueries() { + Query query1 = mock(Query.class); + Query query2 = mock(Query.class); + Criteria criteria = mock(Criteria.class); + given(session.createQuery("some query")).willReturn(query1); + given(query1.setCacheable(true)).willReturn(query1); + given(session.getNamedQuery("some query name")).willReturn(query2); + given(query2.setCacheable(true)).willReturn(query2); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setCacheable(true)).willReturn(criteria); + + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session sess) { + assertNotSame(session, sess); + assertTrue(Proxy.isProxyClass(sess.getClass())); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + // should be ignored + sess.close(); + return null; + } + }); + } + + @Test + public void testExecuteWithCacheQueriesAndCacheRegion() { + Query query1 = mock(Query.class); + Query query2 = mock(Query.class); + Criteria criteria = mock(Criteria.class); + given(session.createQuery("some query")).willReturn(query1); + given(query1.setCacheable(true)).willReturn(query1); + given(query1.setCacheRegion("myRegion")).willReturn(query1); + given(session.getNamedQuery("some query name")).willReturn(query2); + given(query2.setCacheable(true)).willReturn(query2); + given(query2.setCacheRegion("myRegion")).willReturn(query2); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setCacheable(true)).willReturn(criteria); + given(criteria.setCacheRegion("myRegion")).willReturn(criteria); + + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.setQueryCacheRegion("myRegion"); + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session sess) { + assertNotSame(session, sess); + assertTrue(Proxy.isProxyClass(sess.getClass())); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + // should be ignored + sess.close(); + return null; + } + }); + } + + @Test + public void testExecuteWithCacheQueriesAndCacheRegionAndNativeSession() { + Query query1 = mock(Query.class); + Query query2 = mock(Query.class); + Criteria criteria = mock(Criteria.class); + + given(session.createQuery("some query")).willReturn(query1); + given(session.getNamedQuery("some query name")).willReturn(query2); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + + hibernateTemplate.setExposeNativeSession(true); + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.setQueryCacheRegion("myRegion"); + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session sess) { + assertSame(session, sess); + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + return null; + } + }); + } + + @Test + public void testExecuteWithFetchSizeAndMaxResults() { + Query query1 = mock(Query.class); + Query query2 = mock(Query.class); + Criteria criteria = mock(Criteria.class); + + given(session.createQuery("some query")).willReturn(query1); + given(query1.setFetchSize(10)).willReturn(query1); + given(query1.setMaxResults(20)).willReturn(query1); + given(session.getNamedQuery("some query name")).willReturn(query2); + given(query2.setFetchSize(10)).willReturn(query2); + given(query2.setMaxResults(20)).willReturn(query2); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setFetchSize(10)).willReturn(criteria); + given(criteria.setMaxResults(20)).willReturn(criteria); + + hibernateTemplate.setFetchSize(10); + hibernateTemplate.setMaxResults(20); + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session sess) { + sess.createQuery("some query"); + sess.getNamedQuery("some query name"); + sess.createCriteria(TestBean.class); + return null; + } + }); + } + + @Test + public void testGet() { + TestBean tb = new TestBean(); + given(session.get(TestBean.class, "")).willReturn(tb); + Object result = hibernateTemplate.get(TestBean.class, ""); + assertTrue("Correct result", result == tb); + } + + @Test + public void testGetWithEntityName() { + TestBean tb = new TestBean(); + given(session.get("myEntity", "")).willReturn(tb); + Object result = hibernateTemplate.get("myEntity", ""); + assertTrue("Correct result", result == tb); + } + + @Test + public void testLoad() { + TestBean tb = new TestBean(); + given(session.load(TestBean.class, "")).willReturn(tb); + Object result = hibernateTemplate.load(TestBean.class, ""); + assertTrue("Correct result", result == tb); + } + + @Test + public void testLoadWithNotFound() { + ObjectNotFoundException onfex = new ObjectNotFoundException("id", TestBean.class.getName()); + given(session.load(TestBean.class, "id")).willThrow(onfex); + try { + hibernateTemplate.load(TestBean.class, "id"); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(onfex, ex.getCause()); + } + } + + @Test + public void testLoadWithEntityName() { + TestBean tb = new TestBean(); + given(session.load("myEntity", "")).willReturn(tb); + Object result = hibernateTemplate.load("myEntity", ""); + assertTrue("Correct result", result == tb); + } + + @Test + public void testLoadWithObject() { + TestBean tb = new TestBean(); + hibernateTemplate.load(tb, ""); + verify(session).load(tb, ""); + } + + @Test + public void testLoadAll() { + Criteria criteria = mock(Criteria.class); + List list = new ArrayList(); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).willReturn(criteria); + given(criteria.list()).willReturn(list); + List result = hibernateTemplate.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + } + + @Test + public void testLoadAllWithCacheable() { + Criteria criteria = mock(Criteria.class); + List list = new ArrayList(); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).willReturn(criteria); + given(criteria.setCacheable(true)).willReturn(criteria); + given(criteria.list()).willReturn(list); + + hibernateTemplate.setCacheQueries(true); + List result = hibernateTemplate.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + verify(criteria).setCacheable(true); + } + + @Test + public void testLoadAllWithCacheableAndCacheRegion() { + Criteria criteria = mock(Criteria.class); + List list = new ArrayList(); + given(session.createCriteria(TestBean.class)).willReturn(criteria); + given(criteria.setResultTransformer(Criteria.DISTINCT_ROOT_ENTITY)).willReturn(criteria); + given(criteria.setCacheable(true)).willReturn(criteria); + given(criteria.setCacheRegion("myCacheRegion")).willReturn(criteria); + given(criteria.list()).willReturn(list); + + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.setQueryCacheRegion("myCacheRegion"); + List result = hibernateTemplate.loadAll(TestBean.class); + assertTrue("Correct result", result == list); + verify(criteria).setCacheable(true); + verify(criteria).setCacheRegion("myCacheRegion"); + } + + @Test public void testRefresh() { + TestBean tb = new TestBean(); + hibernateTemplate.refresh(tb); + verify(session).refresh(tb); + } + + @Test public void testContains() { + TestBean tb = new TestBean(); + given(session.contains(tb)).willReturn(true); + assertTrue(hibernateTemplate.contains(tb)); + } + + @Test + public void testEvict() { + TestBean tb = new TestBean(); + hibernateTemplate.evict(tb); + verify(session).evict(tb); + } + + @Test + public void testSave() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + given(session.save(tb)).willReturn(0); + assertEquals("Correct return value", hibernateTemplate.save(tb), 0); + } + + @Test + public void testSaveWithEntityName() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + given(session.save("myEntity", tb)).willReturn(0); + assertEquals("Correct return value", hibernateTemplate.save("myEntity", tb), 0); + } + + @Test + public void testUpdate() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.update(tb); + verify(session).update(tb); + } + + @Test + public void testUpdateWithEntityName() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.update("myEntity", tb); + verify(session).update("myEntity", tb); + } + + @Test + public void testSaveOrUpdate() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.saveOrUpdate(tb); + verify(session).saveOrUpdate(tb); + } + + @Test + public void testSaveOrUpdateWithFlushModeNever() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.MANUAL); + try { + hibernateTemplate.saveOrUpdate(tb); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + } + + @Test + public void testSaveOrUpdateWithEntityName() { + TestBean tb = new TestBean(); + + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.saveOrUpdate("myEntity", tb); + verify(session).saveOrUpdate("myEntity", tb); + } + + @Test + public void testReplicate() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.replicate(tb, ReplicationMode.LATEST_VERSION); + verify(session).replicate(tb, ReplicationMode.LATEST_VERSION); + } + + @Test + public void testReplicateWithEntityName() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.replicate("myEntity", tb, ReplicationMode.LATEST_VERSION); + verify(session).replicate("myEntity", tb, ReplicationMode.LATEST_VERSION); + } + + @Test + public void testPersist() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.persist(tb); + verify(session).persist(tb); + } + + @Test + public void testPersistWithEntityName() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.persist("myEntity", tb); + verify(session).persist("myEntity", tb); + } + + @Test + public void testMerge() { + TestBean tb = new TestBean(); + TestBean tbMerged = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + given(session.merge(tb)).willReturn(tbMerged); + assertSame(tbMerged, hibernateTemplate.merge(tb)); + } + + @Test + public void testMergeWithEntityName() { + TestBean tb = new TestBean(); + TestBean tbMerged = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + given(session.merge("myEntity", tb)).willReturn(tbMerged); + assertSame(tbMerged, hibernateTemplate.merge("myEntity", tb)); + } + + @Test + public void testDelete() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.delete(tb); + verify(session).delete(tb); + } + + @Test + public void testDeleteWithEntityName() { + TestBean tb = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + hibernateTemplate.delete("myEntity", tb); + verify(session).delete("myEntity", tb); + } + + @Test + public void testDeleteAll() { + TestBean tb1 = new TestBean(); + TestBean tb2 = new TestBean(); + given(session.getFlushMode()).willReturn(FlushMode.AUTO); + List tbs = new ArrayList(); + tbs.add(tb1); + tbs.add(tb2); + hibernateTemplate.deleteAll(tbs); + verify(session).delete(same(tb1)); + verify(session).delete(same(tb2)); + } + + @Test + public void testFlush() { + hibernateTemplate.flush(); + verify(session).flush(); + } + + @Test + public void testClear() { + hibernateTemplate.clear(); + verify(session).clear(); + } + + @Test + public void testFind() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.find("some query string"); + assertTrue("Correct list", result == list); + } + + @Test + public void testFindWithParameter() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.find("some query string", "myvalue"); + assertTrue("Correct list", result == list); + verify(query).setParameter(0, "myvalue"); + } + + @Test + public void testFindWithParameters() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue1")).willReturn(query); + given(query.setParameter(1, 2)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.find("some query string", "myvalue1", 2); + assertTrue("Correct list", result == list); + verify(query).setParameter(0, "myvalue1"); + verify(query).setParameter(1, 2); + } + + @Test + public void testFindWithNamedParameter() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter("myparam", "myvalue")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedParam("some query string", "myparam", "myvalue"); + assertTrue("Correct list", result == list); + verify(query).setParameter("myparam", "myvalue"); + } + + @Test + public void testFindWithNamedParameters() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter("myparam1", "myvalue1")).willReturn(query); + given(query.setParameter("myparam2", 2)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedParam("some query string", + new String[]{"myparam1", "myparam2"}, + new Object[]{"myvalue1", 2}); + assertTrue("Correct list", result == list); + verify(query).setParameter("myparam1", "myvalue1"); + verify(query).setParameter("myparam2", 2); + } + + @Test + public void testFindByValueBean() { + Query query = mock(Query.class); + TestBean tb = new TestBean(); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setProperties(tb)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByValueBean("some query string", tb); + assertTrue("Correct list", result == list); + verify(query).setProperties(tb); + } + + @Test + public void testFindByNamedQuery() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + } + + @Test + public void testFindByNamedQueryWithParameter() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setParameter(0, "myvalue")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQuery("some query name", "myvalue"); + assertTrue("Correct list", result == list); + verify(query).setParameter(0, "myvalue"); + } + + @Test + public void testFindByNamedQueryWithParameters() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setParameter(0, "myvalue1")).willReturn(query); + given(query.setParameter(1, 2)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQuery("some query name", new Object[] {"myvalue1", 2}); + assertTrue("Correct list", result == list); + verify(query).setParameter(0, "myvalue1"); + verify(query).setParameter(1, 2); + } + + @Test + public void testFindByNamedQueryWithNamedParameter() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setParameter("myparam", "myvalue")).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQueryAndNamedParam("some query name", "myparam", "myvalue"); + assertTrue("Correct list", result == list); + verify(query).setParameter("myparam", "myvalue"); + } + + @Test + public void testFindByNamedQueryWithNamedParameters() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setParameter("myparam1", "myvalue1")).willReturn(query); + given(query.setParameter("myparam2", 2)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQueryAndNamedParam("some query name", + new String[]{"myparam1", "myparam2"}, + new Object[]{"myvalue1", 2}); + assertTrue("Correct list", result == list); + verify(query).setParameter("myparam1", "myvalue1"); + verify(query).setParameter("myparam2", 2); + } + + @Test + public void testFindByNamedQueryAndValueBean() { + Query query = mock(Query.class); + TestBean tb = new TestBean(); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setProperties(tb)).willReturn(query); + given(query.list()).willReturn(list); + List result = hibernateTemplate.findByNamedQueryAndValueBean("some query name", tb); + assertTrue("Correct list", result == list); + verify(query).setProperties(tb); + } + + @Test + public void testFindWithCacheable() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setCacheable(true)).willReturn(query); + given(query.list()).willReturn(list); + hibernateTemplate.setCacheQueries(true); + List result = hibernateTemplate.find("some query string"); + assertTrue("Correct list", result == list); + verify(query).setCacheable(true); + } + + @Test + public void testFindWithCacheableAndCacheRegion() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setCacheable(true)).willReturn(query); + given(query.setCacheRegion("myCacheRegion")).willReturn(query); + given(query.list()).willReturn(list); + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.setQueryCacheRegion("myCacheRegion"); + List result = hibernateTemplate.find("some query string"); + assertTrue("Correct list", result == list); + verify(query).setCacheable(true); + verify(query).setCacheRegion("myCacheRegion"); + } + + @Test + public void testFindByNamedQueryWithCacheable() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setCacheable(true)).willReturn(query); + given(query.list()).willReturn(list); + hibernateTemplate.setCacheQueries(true); + List result = hibernateTemplate.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + verify(query).setCacheable(true); + } + + @Test + public void testFindByNamedQueryWithCacheableAndCacheRegion() { + Query query = mock(Query.class); + List list = new ArrayList(); + given(session.getNamedQuery("some query name")).willReturn(query); + given(query.setCacheable(true)).willReturn(query); + given(query.setCacheRegion("myCacheRegion")).willReturn(query); + given(query.list()).willReturn(list); + hibernateTemplate.setCacheQueries(true); + hibernateTemplate.setQueryCacheRegion("myCacheRegion"); + List result = hibernateTemplate.findByNamedQuery("some query name"); + assertTrue("Correct list", result == list); + verify(query).setCacheable(true); + verify(query).setCacheRegion("myCacheRegion"); + } + + @Test + public void testIterate() { + Query query = mock(Query.class); + Iterator it = Collections.EMPTY_LIST.iterator(); + given(session.createQuery("some query string")).willReturn(query); + given(query.iterate()).willReturn(it); + Iterator result = hibernateTemplate.iterate("some query string"); + assertTrue("Correct list", result == it); + } + + @Test + public void testIterateWithParameter() { + Query query = mock(Query.class); + Iterator it = Collections.EMPTY_LIST.iterator(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue")).willReturn(query); + given(query.iterate()).willReturn(it); + Iterator result = hibernateTemplate.iterate("some query string", "myvalue"); + assertTrue("Correct list", result == it); + verify(query).setParameter(0, "myvalue"); + } + + @Test + public void testIterateWithParameters() { + Query query = mock(Query.class); + Iterator it = Collections.EMPTY_LIST.iterator(); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue1")).willReturn(query); + given(query.setParameter(1, 2)).willReturn(query); + given(query.iterate()).willReturn(it); + Iterator result = hibernateTemplate.iterate("some query string", "myvalue1", 2); + assertTrue("Correct list", result == it); + verify(query).setParameter(0, "myvalue1"); + verify(query).setParameter(1, 2); + } + + @Test + public void testBulkUpdate() { + Query query = mock(Query.class); + given(session.createQuery("some query string")).willReturn(query); + given(query.executeUpdate()).willReturn(5); + int result = hibernateTemplate.bulkUpdate("some query string"); + assertTrue("Correct list", result == 5); + } + + @Test + public void testBulkUpdateWithParameter() { + Query query = mock(Query.class); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue")).willReturn(query); + given(query.executeUpdate()).willReturn(5); + int result = hibernateTemplate.bulkUpdate("some query string", "myvalue"); + assertTrue("Correct list", result == 5); + verify(query).setParameter(0, "myvalue"); + } + + @Test + public void testBulkUpdateWithParameters() { + Query query = mock(Query.class); + given(session.createQuery("some query string")).willReturn(query); + given(query.setParameter(0, "myvalue1")).willReturn(query); + given(query.setParameter(1, 2)).willReturn(query); + given(query.executeUpdate()).willReturn(5); + int result = hibernateTemplate.bulkUpdate("some query string", "myvalue1", 2); + assertTrue("Correct list", result == 5); + verify(query).setParameter(0, "myvalue1"); + verify(query).setParameter(1, 2); + } + + @Test + public void testExceptions() { + SQLException sqlEx = new SQLException("argh", "27"); + + final JDBCConnectionException jcex = new JDBCConnectionException("mymsg", sqlEx); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw jcex; + } + }); + fail("Should have thrown DataAccessResourceFailureException"); + } + catch (DataAccessResourceFailureException ex) { + // expected + assertEquals(jcex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final SQLGrammarException sgex = new SQLGrammarException("mymsg", sqlEx); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw sgex; + } + }); + fail("Should have thrown InvalidDataAccessResourceUsageException"); + } + catch (InvalidDataAccessResourceUsageException ex) { + // expected + assertEquals(sgex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final LockAcquisitionException laex = new LockAcquisitionException("mymsg", sqlEx); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw laex; + } + }); + fail("Should have thrown CannotAcquireLockException"); + } + catch (CannotAcquireLockException ex) { + // expected + assertEquals(laex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final ConstraintViolationException cvex = new ConstraintViolationException("mymsg", sqlEx, "myconstraint"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw cvex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(cvex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final DataException dex = new DataException("mymsg", sqlEx); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw dex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(dex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final JDBCException jdex = new JDBCException("mymsg", sqlEx); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw jdex; + } + }); + fail("Should have thrown HibernateJdbcException"); + } + catch (HibernateJdbcException ex) { + // expected + assertEquals(jdex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + final PropertyValueException pvex = new PropertyValueException("mymsg", "myentity", "myproperty"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw pvex; + } + }); + fail("Should have thrown DataIntegrityViolationException"); + } + catch (DataIntegrityViolationException ex) { + // expected + assertEquals(pvex, ex.getCause()); + assertTrue(ex.getMessage().contains("mymsg")); + } + + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw new PersistentObjectException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw new TransientObjectException(""); + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + } + + final ObjectDeletedException odex = new ObjectDeletedException("msg", "id", TestBean.class.getName()); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw odex; + } + }); + fail("Should have thrown InvalidDataAccessApiUsageException"); + } + catch (InvalidDataAccessApiUsageException ex) { + // expected + assertEquals(odex, ex.getCause()); + } + + final QueryException qex = new QueryException("msg", "query"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw qex; + } + }); + fail("Should have thrown InvalidDataAccessResourceUsageException"); + } + catch (HibernateQueryException ex) { + // expected + assertEquals(qex, ex.getCause()); + assertEquals("query", ex.getQueryString()); + } + + final UnresolvableObjectException uoex = new UnresolvableObjectException("id", TestBean.class.getName()); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw uoex; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(uoex, ex.getCause()); + } + + final ObjectNotFoundException onfe = new ObjectNotFoundException("id", TestBean.class.getName()); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw onfe; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(onfe, ex.getCause()); + } + + final WrongClassException wcex = new WrongClassException("msg", "id", TestBean.class.getName()); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw wcex; + } + }); + fail("Should have thrown HibernateObjectRetrievalFailureException"); + } + catch (HibernateObjectRetrievalFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(wcex, ex.getCause()); + } + + final NonUniqueResultException nuex = new NonUniqueResultException(2); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw nuex; + } + }); + fail("Should have thrown IncorrectResultSizeDataAccessException"); + } + catch (IncorrectResultSizeDataAccessException ex) { + // expected + assertEquals(1, ex.getExpectedSize()); + assertEquals(-1, ex.getActualSize()); + } + + final StaleObjectStateException sosex = new StaleObjectStateException(TestBean.class.getName(), "id"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw sosex; + } + }); + fail("Should have thrown HibernateOptimisticLockingFailureException"); + } + catch (HibernateOptimisticLockingFailureException ex) { + // expected + assertEquals(TestBean.class.getName(), ex.getPersistentClassName()); + assertEquals("id", ex.getIdentifier()); + assertEquals(sosex, ex.getCause()); + } + + final StaleStateException ssex = new StaleStateException("msg"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw ssex; + } + }); + fail("Should have thrown HibernateOptimisticLockingFailureException"); + } + catch (HibernateOptimisticLockingFailureException ex) { + // expected + assertNull(ex.getPersistentClassName()); + assertNull(ex.getIdentifier()); + assertEquals(ssex, ex.getCause()); + } + + final HibernateException hex = new HibernateException("msg"); + try { + hibernateTemplate.execute(new HibernateCallback() { + @Override + public Object doInHibernate(Session session) { + throw hex; + } + }); + fail("Should have thrown HibernateSystemException"); + } + catch (HibernateSystemException ex) { + // expected + assertEquals(hex, ex.getCause()); + } + } + +} diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java index fb0dc74444a..5383b80a81c 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateAccessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -289,7 +289,7 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory * @see org.hibernate.Session#enableFilter(String) * @see LocalSessionFactoryBean#setFilterDefinitions */ - public void setFilterNames(String[] filterNames) { + public void setFilterNames(String... filterNames) { this.filterNames = filterNames; } @@ -466,8 +466,8 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory protected void enableFilters(Session session) { String[] filterNames = getFilterNames(); if (filterNames != null) { - for (int i = 0; i < filterNames.length; i++) { - session.enableFilter(filterNames[i]); + for (String filterName : filterNames) { + session.enableFilter(filterName); } } } @@ -481,8 +481,8 @@ public abstract class HibernateAccessor implements InitializingBean, BeanFactory protected void disableFilters(Session session) { String[] filterNames = getFilterNames(); if (filterNames != null) { - for (int i = 0; i < filterNames.length; i++) { - session.disableFilter(filterNames[i]); + for (String filterName : filterNames) { + session.disableFilter(filterName); } } } diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateInterceptor.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateInterceptor.java index 91d5a4524f5..7d412f693a9 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateInterceptor.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateInterceptor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -68,7 +68,12 @@ import org.springframework.transaction.support.TransactionSynchronizationManager * @see org.hibernate.SessionFactory#getCurrentSession() * @see HibernateTransactionManager * @see HibernateTemplate + * @deprecated as of Spring 3.2.7, in favor of either HibernateTemplate usage or + * native Hibernate API usage within transactions, in combination with a general + * {@link org.springframework.dao.annotation.PersistenceExceptionTranslationPostProcessor}. + * Note: This class does not have an equivalent replacement in {@code orm.hibernate4}. */ +@Deprecated public class HibernateInterceptor extends HibernateAccessor implements MethodInterceptor { private boolean exceptionConversionEnabled = true; diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateOperations.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateOperations.java index 3647ca8bb86..38ffae9dec7 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateOperations.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateOperations.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -90,10 +90,13 @@ public interface HibernateOperations { * {@link List}. *

This is a convenience method for executing Hibernate find calls or * queries within an action. - * @param action calback object that specifies the Hibernate action + * @param action callback object that specifies the Hibernate action * @return a List result returned by the action, or {@code null} * @throws org.springframework.dao.DataAccessException in case of Hibernate errors + * @deprecated as of Spring 3.2.7, in favor of using a regular {@link #execute} + * call with a generic List type declared */ + @Deprecated List executeFind(HibernateCallback action) throws DataAccessException; @@ -131,8 +134,7 @@ public interface HibernateOperations { * @throws org.springframework.dao.DataAccessException in case of Hibernate errors * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode) */ - T get(Class entityClass, Serializable id, LockMode lockMode) - throws DataAccessException; + T get(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; /** * Return the persistent instance of the given entity class @@ -164,8 +166,7 @@ public interface HibernateOperations { * @throws org.springframework.dao.DataAccessException in case of Hibernate errors * @see org.hibernate.Session#get(Class, java.io.Serializable, org.hibernate.LockMode) */ - Object get(String entityName, Serializable id, LockMode lockMode) - throws DataAccessException; + Object get(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; /** * Return the persistent instance of the given entity class @@ -199,8 +200,7 @@ public interface HibernateOperations { * @throws org.springframework.dao.DataAccessException in case of Hibernate errors * @see org.hibernate.Session#load(Class, java.io.Serializable) */ - T load(Class entityClass, Serializable id, LockMode lockMode) - throws DataAccessException; + T load(Class entityClass, Serializable id, LockMode lockMode) throws DataAccessException; /** * Return the persistent instance of the given entity class @@ -234,8 +234,7 @@ public interface HibernateOperations { * @throws org.springframework.dao.DataAccessException in case of Hibernate errors * @see org.hibernate.Session#load(Class, java.io.Serializable) */ - Object load(String entityName, Serializable id, LockMode lockMode) - throws DataAccessException; + Object load(String entityName, Serializable id, LockMode lockMode) throws DataAccessException; /** * Return all persistent instances of the given entity class. diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java index 3e4c7dfc26c..c416494de05 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/HibernateTemplate.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2014 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. @@ -40,6 +40,7 @@ import org.hibernate.criterion.DetachedCriteria; import org.hibernate.criterion.Example; import org.hibernate.engine.SessionImplementor; import org.hibernate.event.EventSource; + import org.springframework.dao.DataAccessException; import org.springframework.dao.DataAccessResourceFailureException; import org.springframework.dao.InvalidDataAccessApiUsageException; @@ -132,7 +133,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe /** * Create a new HibernateTemplate instance. - * @param sessionFactory SessionFactory to create Sessions + * @param sessionFactory the SessionFactory to create Sessions with */ public HibernateTemplate(SessionFactory sessionFactory) { setSessionFactory(sessionFactory); @@ -141,7 +142,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe /** * Create a new HibernateTemplate instance. - * @param sessionFactory SessionFactory to create Sessions + * @param sessionFactory the SessionFactory to create Sessions with * @param allowCreate if a non-transactional Session should be created when no * transactional Session can be found for the current thread */ @@ -341,6 +342,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe } @Override + @Deprecated @SuppressWarnings("unchecked") public List executeFind(HibernateCallback action) throws DataAccessException { Object result = doExecute(action, false, false); @@ -1077,7 +1079,7 @@ public class HibernateTemplate extends HibernateAccessor implements HibernateOpe final String queryName, final String[] paramNames, final Object[] values) throws DataAccessException { - if (paramNames != null && values != null && paramNames.length != values.length) { + if (values != null && (paramNames == null || paramNames.length != values.length)) { throw new IllegalArgumentException("Length of paramNames array must match length of values array"); } return executeWithNativeSession(new HibernateCallback>() { diff --git a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java index e495fc8a9c7..3b7fc1468d2 100644 --- a/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java +++ b/spring-orm/src/main/java/org/springframework/orm/hibernate3/support/HibernateDaoSupport.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2014 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. @@ -46,6 +46,11 @@ import org.springframework.orm.hibernate3.SessionFactoryUtils; * by default. A custom HibernateTemplate instance can be used through overriding * {@link #createHibernateTemplate}. * + *

NOTE: As of Hibernate 3.0.1, transactional Hibernate access code can + * also be coded in plain Hibernate style. Hence, for newly started projects, + * consider adopting the standard Hibernate3 style of coding data access objects + * instead, based on {@link org.hibernate.SessionFactory#getCurrentSession()}. + * * @author Juergen Hoeller * @since 1.2 * @see #setSessionFactory @@ -105,8 +110,8 @@ public abstract class HibernateDaoSupport extends DaoSupport { * You may introspect its configuration, but not modify the configuration * (other than from within an {@link #initDao} implementation). * Consider creating a custom HibernateTemplate instance via - * {@code new HibernateTemplate(getSessionFactory())}, in which - * case you're allowed to customize the settings on the resulting instance. + * {@code new HibernateTemplate(getSessionFactory())}, in which case + * you're allowed to customize the settings on the resulting instance. */ public final HibernateTemplate getHibernateTemplate() { return this.hibernateTemplate; @@ -136,10 +141,10 @@ public abstract class HibernateDaoSupport extends DaoSupport { * @throws DataAccessResourceFailureException if the Session couldn't be created * @throws IllegalStateException if no thread-bound Session found and allowCreate=false * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean) + * @deprecated as of Spring 3.2.7, in favor of {@link HibernateTemplate} usage */ - protected final Session getSession() - throws DataAccessResourceFailureException, IllegalStateException { - + @Deprecated + protected final Session getSession() throws DataAccessResourceFailureException, IllegalStateException { return getSession(this.hibernateTemplate.isAllowCreate()); } @@ -161,9 +166,11 @@ public abstract class HibernateDaoSupport extends DaoSupport { * @throws DataAccessResourceFailureException if the Session couldn't be created * @throws IllegalStateException if no thread-bound Session found and allowCreate=false * @see org.springframework.orm.hibernate3.SessionFactoryUtils#getSession(SessionFactory, boolean) + * @deprecated as of Spring 3.2.7, in favor of {@link HibernateTemplate} usage */ + @Deprecated protected final Session getSession(boolean allowCreate) - throws DataAccessResourceFailureException, IllegalStateException { + throws DataAccessResourceFailureException, IllegalStateException { return (!allowCreate ? SessionFactoryUtils.getSession(getSessionFactory(), false) : @@ -185,7 +192,9 @@ public abstract class HibernateDaoSupport extends DaoSupport { * @param ex HibernateException that occurred * @return the corresponding DataAccessException instance * @see org.springframework.orm.hibernate3.SessionFactoryUtils#convertHibernateAccessException + * @deprecated as of Spring 3.2.7, in favor of {@link HibernateTemplate} usage */ + @Deprecated protected final DataAccessException convertHibernateAccessException(HibernateException ex) { return this.hibernateTemplate.convertHibernateAccessException(ex); } @@ -197,7 +206,9 @@ public abstract class HibernateDaoSupport extends DaoSupport { * {@link #getSession} and {@link #convertHibernateAccessException}. * @param session the Session to close * @see org.springframework.orm.hibernate3.SessionFactoryUtils#releaseSession + * @deprecated as of Spring 3.2.7, in favor of {@link HibernateTemplate} usage */ + @Deprecated protected final void releaseSession(Session session) { SessionFactoryUtils.releaseSession(session, getSessionFactory()); }