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

org.hibernate.query.spi.AbstractQuery Maven / Gradle / Ivy

There is a newer version: 7.0.0.Beta1
Show newest version
/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * License: GNU Lesser General Public License (LGPL), version 2.1 or later
 * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
 */
package org.hibernate.query.spi;

import java.io.Serializable;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import javax.persistence.CacheRetrieveMode;
import javax.persistence.CacheStoreMode;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.Parameter;
import javax.persistence.TemporalType;
import javax.persistence.TransactionRequiredException;

import org.hibernate.CacheMode;
import org.hibernate.FlushMode;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.NonUniqueResultException;
import org.hibernate.PropertyNotFoundException;
import org.hibernate.ScrollMode;
import org.hibernate.TypeMismatchException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.EntityManagerMessageLogger;
import org.hibernate.internal.HEMLogging;
import org.hibernate.jpa.QueryHints;
import org.hibernate.jpa.internal.util.CacheModeHelper;
import org.hibernate.jpa.internal.util.ConfigurationHelper;
import org.hibernate.jpa.internal.util.FlushModeTypeHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.property.access.spi.BuiltInPropertyAccessStrategies;
import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.PropertyAccess;
import org.hibernate.query.IllegalQueryOperationException;
import org.hibernate.query.ParameterMetadata;
import org.hibernate.query.QueryParameter;
import org.hibernate.query.ResultListTransformer;
import org.hibernate.query.TupleTransformer;
import org.hibernate.query.TypedParameterValue;
import org.hibernate.query.internal.ScrollableResultsIterator;
import org.hibernate.query.named.NamedQueryMemento;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;

import static org.hibernate.LockOptions.WAIT_FOREVER;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE;
import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_STORE_MODE;
import static org.hibernate.internal.util.NullnessHelper.nullif;
import static org.hibernate.jpa.AvailableSettings.ALIAS_SPECIFIC_LOCK_MODE;
import static org.hibernate.jpa.QueryHints.HINT_CACHEABLE;
import static org.hibernate.jpa.QueryHints.HINT_CACHE_MODE;
import static org.hibernate.jpa.QueryHints.HINT_CACHE_REGION;
import static org.hibernate.jpa.QueryHints.HINT_COMMENT;
import static org.hibernate.jpa.QueryHints.HINT_FETCHGRAPH;
import static org.hibernate.jpa.QueryHints.HINT_FETCH_SIZE;
import static org.hibernate.jpa.QueryHints.HINT_FLUSH_MODE;
import static org.hibernate.jpa.QueryHints.HINT_FOLLOW_ON_LOCKING;
import static org.hibernate.jpa.QueryHints.HINT_LOADGRAPH;
import static org.hibernate.jpa.QueryHints.HINT_READONLY;
import static org.hibernate.jpa.QueryHints.HINT_TIMEOUT;
import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT;

/**
 * @author Steve Ebersole
 */
@SuppressWarnings("WeakerAccess")
public abstract class AbstractQuery implements QueryImplementor {
	private static final EntityManagerMessageLogger log = HEMLogging.messageLogger( AbstractQuery.class );

	private final SharedSessionContractImplementor session;

	public AbstractQuery(SharedSessionContractImplementor session) {
		this.session = session;
	}

	protected void applyOptions(NamedQueryMemento memento) {
		if ( memento.getHints() != null ) {
			memento.getHints().forEach( this::setHint );
		}

		if ( memento.getCacheable() != null ) {
			setCacheable( memento.getCacheable() );
		}

		if ( memento.getCacheRegion() != null ) {
			setCacheRegion( memento.getCacheRegion() );
		}

		if ( memento.getCacheMode() != null ) {
			setCacheMode( memento.getCacheMode() );
		}

		if ( memento.getFlushMode() != null ) {
			setHibernateFlushMode( memento.getFlushMode() );
		}

		if ( memento.getReadOnly() != null ) {
			setReadOnly( memento.getReadOnly() );
		}

		if ( memento.getTimeout() != null ) {
			setTimeout( memento.getTimeout() );
		}

		if ( memento.getFetchSize() != null ) {
			setFetchSize( memento.getFetchSize() );
		}

		if ( memento.getComment() != null ) {
			setComment( memento.getComment() );
		}
	}

	@Override
	public SharedSessionContractImplementor getSession() {
		return session;
	}

	protected abstract boolean canApplyAliasSpecificLockModes();

	protected abstract void verifySettingLockMode();

	protected abstract void verifySettingAliasSpecificLockModes();

	protected abstract QueryParameterBindings getQueryParameterBindings();

	@Override
	public abstract ParameterMetadataImplementor getParameterMetadata();


	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// QueryOptions handling

	@Override
	public abstract MutableQueryOptions getQueryOptions();


	@Override
	public int getMaxResults() {
		return getQueryOptions().getLimit().getMaxRowsJpa();
	}

	@Override
	public QueryImplementor setMaxResults(int maxResult) {
		getQueryOptions().getLimit().setMaxRows( maxResult );
		return this;
	}

	@Override
	public int getFirstResult() {
		return getQueryOptions().getLimit().getFirstRowJpa();
	}

	@Override
	public QueryImplementor setFirstResult(int startPosition) {
		getQueryOptions().getLimit().setFirstRow( startPosition );
		return this;
	}

	@Override
	public QueryImplementor setTupleTransformer(TupleTransformer transformer) {
		getQueryOptions().setTupleTransformer( transformer );
		return this;
	}

	@Override
	public QueryImplementor setResultListTransformer(ResultListTransformer transformer) {
		getQueryOptions().setResultListTransformer( transformer );
		return this;
	}

	@Override
	public LockModeType getLockMode() {
		return LockModeTypeHelper.getLockModeType( getQueryOptions().getLockOptions().getLockMode() );
	}

	@Override
	public FlushMode getHibernateFlushMode() {
		return getQueryOptions().getFlushMode();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setHibernateFlushMode(FlushMode flushMode) {
		getQueryOptions().setFlushMode( flushMode );
		return this;
	}

	@Override
	public FlushModeType getFlushMode() {
		final FlushMode flushMode = getQueryOptions().getFlushMode() == null
				? getSession().getHibernateFlushMode()
				: getQueryOptions().getFlushMode();
		return FlushModeTypeHelper.getFlushModeType( flushMode );
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setFlushMode(FlushModeType flushModeType) {
		setHibernateFlushMode( FlushModeTypeHelper.getFlushMode( flushModeType ) );
		return this;
	}

	@Override
	public CacheMode getCacheMode() {
		return getQueryOptions().getCacheMode();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setCacheMode(CacheMode cacheMode) {
		getQueryOptions().setCacheMode( cacheMode );
		return this;
	}

	@Override
	public boolean isCacheable() {
		return getQueryOptions().isResultCachingEnabled() == Boolean.TRUE;
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setCacheable(boolean cacheable) {
		getQueryOptions().setResultCachingEnabled( cacheable );
		return this;
	}

	@Override
	public String getCacheRegion() {
		return getQueryOptions().getResultCacheRegionName();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setCacheRegion(String cacheRegion) {
		getQueryOptions().setResultCacheRegionName( cacheRegion );
		return this;
	}

	@Override
	public Integer getTimeout() {
		return getQueryOptions().getTimeout();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setTimeout(int timeout) {
		getQueryOptions().setTimeout( timeout );
		return this;
	}

	@Override
	public Integer getFetchSize() {
		return getQueryOptions().getFetchSize();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setFetchSize(int fetchSize) {
		getQueryOptions().setFetchSize( fetchSize );
		return this;
	}

	@Override
	public boolean isReadOnly() {
		return getQueryOptions().isReadOnly() == null
				? getSession().isDefaultReadOnly()
				: getQueryOptions().isReadOnly();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setReadOnly(boolean readOnly) {
		getQueryOptions().setReadOnly( readOnly );
		return this;
	}

	@Override
	public LockOptions getLockOptions() {
		return getQueryOptions().getLockOptions();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setLockOptions(LockOptions lockOptions) {
		getQueryOptions().getLockOptions().setLockMode( lockOptions.getLockMode() );
		getQueryOptions().getLockOptions().setScope( lockOptions.getScope() );
		getQueryOptions().getLockOptions().setTimeOut( lockOptions.getTimeOut() );
		getQueryOptions().getLockOptions().setFollowOnLocking( lockOptions.getFollowOnLocking() );
		return this;
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setLockMode(String alias, LockMode lockMode) {
		if ( !LockMode.NONE.equals( lockMode ) ) {
			verifySettingAliasSpecificLockModes();
		}

		getQueryOptions().getLockOptions().setAliasSpecificLockMode( alias, lockMode );
		return this;
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setLockMode(LockModeType lockModeType) {
		if ( !LockModeType.NONE.equals( lockModeType ) ) {
			verifySettingLockMode();
		}

		getQueryOptions().getLockOptions().setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
		return this;
	}

	@Override
	public String getComment() {
		return getQueryOptions().getComment();
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor setComment(String comment) {
		getQueryOptions().setComment( comment );
		return this;
	}

	@Override
	@SuppressWarnings("unchecked")
	public QueryImplementor addQueryHint(String hint) {
		getQueryOptions().addDatabaseHint( hint );
		return this;
	}


	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// JPA hint handling


	@SuppressWarnings( {"UnusedDeclaration"})
	public Set getSupportedHints() {
		return QueryHints.getDefinedHints();
	}

	@Override
	public Map getHints() {
		// Technically this should rollback, but that's insane :)
		// If the TCK ever adds a check for this, we may need to change this behavior
		getSession().checkOpen( false );

		final Map hints = new HashMap<>();
		collectBaselineHints( hints );
		collectHints( hints );
		return hints;
	}

	@SuppressWarnings("WeakerAccess")
	protected void collectBaselineHints(Map hints) {
		// nothing to do in this form
	}

	protected void collectHints(Map hints) {
		if ( getQueryOptions().getTimeout() != null ) {
			hints.put( HINT_TIMEOUT, getQueryOptions().getTimeout() );
			hints.put( SPEC_HINT_TIMEOUT, getQueryOptions().getTimeout() * 1000 );
		}

		if ( getLockOptions().getTimeOut() != WAIT_FOREVER ) {
			hints.put( JPA_LOCK_TIMEOUT, getLockOptions().getTimeOut() );
		}

		if ( getLockOptions().getScope() ) {
			hints.put( JPA_LOCK_SCOPE, getLockOptions().getScope() );
		}

		if ( getLockOptions().hasAliasSpecificLockModes() ) {
			for ( Map.Entry entry : getLockOptions().getAliasSpecificLocks() ) {
				hints.put(
						ALIAS_SPECIFIC_LOCK_MODE + '.' + entry.getKey(),
						entry.getValue().name()
				);
			}
		}

		putIfNotNull( hints, HINT_COMMENT, getComment() );
		putIfNotNull( hints, HINT_FETCH_SIZE, getQueryOptions().getFetchSize() );
		putIfNotNull( hints, HINT_FLUSH_MODE, getHibernateFlushMode() );

		if ( getCacheMode() != null ) {
			putIfNotNull( hints, HINT_CACHE_MODE, getCacheMode() );
			putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.interpretCacheRetrieveMode( getCacheMode() ) );
			putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.interpretCacheStoreMode( getCacheMode() ) );
		}

		if ( isCacheable() ) {
			hints.put( HINT_CACHEABLE, true );
			putIfNotNull( hints, HINT_CACHE_REGION, getCacheRegion() );
		}

		if ( isReadOnly() ) {
			hints.put( HINT_READONLY, true );
		}
	}

	protected void putIfNotNull(Map hints, String hintName, Enum hintValue) {
		// centralized spot to handle the decision whether to put enums directly into the hints map
		// or whether to put the enum name
		if ( hintValue != null ) {
			hints.put( hintName, hintValue );
//			hints.put( hintName, hintValue.name() );
		}
	}

	protected void putIfNotNull(Map hints, String hintName, Object hintValue) {
		if ( hintValue != null ) {
			hints.put( hintName, hintValue );
		}
	}

	@Override
	public QueryImplementor setHint(String hintName, Object value) {
		getSession().checkOpen( true );
		boolean applied = false;
		try {
			if ( HINT_TIMEOUT.equals( hintName ) ) {
				applied = applyTimeoutHint( ConfigurationHelper.getInteger( value ) );
			}
			else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) {
				// convert milliseconds to seconds
				int timeout = (int)Math.round( ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 );
				applied = applyTimeoutHint( timeout );
			}
			else if ( JPA_LOCK_TIMEOUT.equals( hintName ) ) {
				applied = applyLockTimeoutHint( ConfigurationHelper.getInteger( value ) );
			}
			else if ( HINT_COMMENT.equals( hintName ) ) {
				applied = applyCommentHint( (String) value );
			}
			else if ( HINT_FETCH_SIZE.equals( hintName ) ) {
				applied = applyFetchSizeHint( ConfigurationHelper.getInteger( value ) );
			}
			else if ( HINT_CACHEABLE.equals( hintName ) ) {
				applied = applyCacheableHint( ConfigurationHelper.getBoolean( value ) );
			}
			else if ( HINT_CACHE_REGION.equals( hintName ) ) {
				applied = applyCacheRegionHint( (String) value );
			}
			else if ( HINT_READONLY.equals( hintName ) ) {
				applied = applyReadOnlyHint( ConfigurationHelper.getBoolean( value ) );
			}
			else if ( HINT_FLUSH_MODE.equals( hintName ) ) {
				applied = applyFlushModeHint( ConfigurationHelper.getFlushMode( value ) );
			}
			else if ( HINT_CACHE_MODE.equals( hintName ) ) {
				applied = applyCacheModeHint( ConfigurationHelper.getCacheMode( value ) );
			}
			else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) ) {
				final CacheRetrieveMode retrieveMode = value != null ? CacheRetrieveMode.valueOf( value.toString() ) : null;
				applied = applyJpaCacheRetrieveMode( retrieveMode );
			}
			else if ( JPA_SHARED_CACHE_STORE_MODE.equals( hintName ) ) {
				final CacheStoreMode storeMode = value != null ? CacheStoreMode.valueOf( value.toString() ) : null;
				applied = applyJpaCacheStoreMode( storeMode );
			}
			else if ( QueryHints.HINT_NATIVE_LOCKMODE.equals( hintName ) ) {
				applied = applyNativeQueryLockMode( value );
			}
			else if ( hintName.startsWith( ALIAS_SPECIFIC_LOCK_MODE ) ) {
				if ( canApplyAliasSpecificLockModes() ) {
					// extract the alias
					final String alias = hintName.substring( ALIAS_SPECIFIC_LOCK_MODE.length() + 1 );
					// determine the LockMode
					try {
						final LockMode lockMode = LockModeTypeHelper.interpretLockMode( value );
						applyAliasSpecificLockModeHint( alias, lockMode );
					}
					catch ( Exception e ) {
						log.unableToDetermineLockModeValue( hintName, value );
						applied = false;
					}
				}
				else {
					//noinspection ConstantConditions
					applied = false;
				}
			}
			else if ( HINT_FETCHGRAPH.equals( hintName ) || HINT_LOADGRAPH.equals( hintName ) ) {
				if (value instanceof RootGraphImplementor ) {
					applyEntityGraphQueryHint( hintName, (RootGraphImplementor) value );
				}
				else {
					log.warnf( "The %s hint was set, but the value was not an EntityGraph!", hintName );
				}
				applied = true;
			}
			else if ( HINT_FOLLOW_ON_LOCKING.equals( hintName ) ) {
				applied = applyFollowOnLockingHint( ConfigurationHelper.getBoolean( value ) );
			}
			else {
				log.ignoringUnrecognizedQueryHint( hintName );
			}
		}
		catch ( ClassCastException e ) {
			throw new IllegalArgumentException( "Value for hint" );
		}

		if ( !applied ) {
			log.debugf( "Skipping unsupported query hint [%s]", hintName );
		}

		return this;
	}

	@SuppressWarnings("WeakerAccess")
	protected boolean applyJpaCacheRetrieveMode(CacheRetrieveMode retrieveMode) {
		final CacheMode currentCacheMode = nullif( getCacheMode(), getSession().getCacheMode() );
		setCacheMode(
				CacheModeHelper.interpretCacheMode(
						CacheModeHelper.interpretCacheStoreMode( currentCacheMode ),
						retrieveMode
				)
		);
		return true;
	}

	@SuppressWarnings("WeakerAccess")
	protected boolean applyJpaCacheStoreMode(CacheStoreMode storeMode) {
		final CacheMode currentCacheMode = nullif( getCacheMode(), getSession().getCacheMode() );
		setCacheMode(
				CacheModeHelper.interpretCacheMode(
						storeMode,
						CacheModeHelper.interpretCacheRetrieveMode( currentCacheMode )
				)
		);
		return true;
	}

	protected boolean applyNativeQueryLockMode(Object value) {
		return false;
	}

	/**
	 * Apply the query timeout hint.
	 *
	 * @param timeout The timeout (in seconds!) specified as a hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyTimeoutHint(int timeout) {
		setTimeout( timeout );
		return true;
	}

	/**
	 * Apply the lock timeout (in seconds!) hint
	 *
	 * @param timeout The timeout (in seconds!) specified as a hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyLockTimeoutHint(int timeout) {
		getLockOptions().setTimeOut( timeout );
		return true;
	}

	/**
	 * Apply the comment hint.
	 *
	 * @param comment The comment specified as a hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyCommentHint(String comment) {
		setComment( comment );
		return true;
	}

	/**
	 * Apply the fetch size hint
	 *
	 * @param fetchSize The fetch size specified as a hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyFetchSizeHint(int fetchSize) {
		setFetchSize( fetchSize );
		return true;
	}

	/**
	 * Apply the cacheable (true/false) hint.
	 *
	 * @param isCacheable The value specified as hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyCacheableHint(boolean isCacheable) {
		setCacheable( isCacheable );
		return true;
	}

	/**
	 * Apply the cache region hint
	 *
	 * @param regionName The name of the cache region specified as a hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyCacheRegionHint(String regionName) {
		setCacheRegion( regionName );
		return true;
	}

	/**
	 * Apply the read-only (true/false) hint.
	 *
	 * @param isReadOnly The value specified as hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyReadOnlyHint(boolean isReadOnly) {
		setReadOnly( isReadOnly );
		return true;
	}

	/**
	 * Apply the CacheMode hint.
	 *
	 * @param cacheMode The CacheMode value specified as a hint.
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyCacheModeHint(CacheMode cacheMode) {
		setCacheMode( cacheMode );
		return true;
	}

	/**
	 * Apply the FlushMode hint.
	 *
	 * @param flushMode The FlushMode value specified as hint
	 *
	 * @return {@code true} if the hint was "applied"
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyFlushModeHint(FlushMode flushMode) {
		setHibernateFlushMode( flushMode );
		return true;
	}

	protected boolean applyLockModeTypeHint(LockModeType lockModeType) {
		getLockOptions().setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
		return true;
	}

	protected boolean applyHibernateLockModeHint(LockMode lockMode) {
		getLockOptions().setLockMode( lockMode );
		return true;
	}

	/**
	 * Apply the alias specific lock modes.  Assumes {@link #canApplyAliasSpecificLockModes()} has already been
	 * called and returned {@code true}.
	 *
	 * @param alias The alias to apply the 'lockMode' to.
	 * @param lockMode The LockMode to apply.
	 */
	@SuppressWarnings("WeakerAccess")
	protected void applyAliasSpecificLockModeHint(String alias, LockMode lockMode) {
		getLockOptions().setAliasSpecificLockMode( alias, lockMode );
	}

	protected abstract void applyEntityGraphQueryHint(String hintName, RootGraphImplementor entityGraph);

	/**
	 * Apply the follow-on-locking hint.
	 *
	 * @param followOnLocking The follow-on-locking strategy.
	 */
	@SuppressWarnings("WeakerAccess")
	protected boolean applyFollowOnLockingHint(Boolean followOnLocking) {
		getLockOptions().setFollowOnLocking( followOnLocking );
		return true;
	}





	// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	// QueryParameter handling

	@Override
	@SuppressWarnings("unchecked")
	public Set> getParameters() {
		return (Set) ( (ParameterMetadata) getParameterMetadata() ).getRegistrations();
	}

	@Override
	public Parameter getParameter(String name) {
		try {
			return getParameterMetadata().getQueryParameter( name );
		}
		catch ( HibernateException e ) {
			throw getSession().getExceptionConverter().convert( e );
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public  Parameter getParameter(String name, Class type) {
		try {
			final QueryParameter parameter = getParameterMetadata().getQueryParameter( name );
			if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
				throw new IllegalArgumentException(
						"The type [" + parameter.getParameterType().getName() +
								"] associated with the parameter corresponding to name [" + name +
								"] is not assignable to requested Java type [" + type.getName() + "]"
				);
			}
			return parameter;
		}
		catch ( HibernateException e ) {
			throw getSession().getExceptionConverter().convert( e );
		}
	}

	@Override
	public Parameter getParameter(int position) {
		try {
			return getParameterMetadata().getQueryParameter( position );
		}
		catch ( HibernateException e ) {
			throw getSession().getExceptionConverter().convert( e );
		}
	}

	@Override
	@SuppressWarnings("unchecked")
	public  Parameter getParameter(int position, Class type) {
		try {
			final QueryParameter parameter = getParameterMetadata().getQueryParameter( position );
			if ( !parameter.getParameterType().isAssignableFrom( type ) ) {
				throw new IllegalArgumentException(
						"The type [" + parameter.getParameterType().getName() +
								"] associated with the parameter corresponding to position [" + position +
								"] is not assignable to requested Java type [" + type.getName() + "]"
				);
			}
			return parameter;
		}
		catch ( HibernateException e ) {
			throw getSession().getExceptionConverter().convert( e );
		}
	}

	@Override
	public boolean isBound(Parameter param) {
		final QueryParameterImplementor qp = getParameterMetadata().resolve( param );
		return qp != null && getQueryParameterBindings().isBound( qp );
	}

	@SuppressWarnings("WeakerAccess")
	protected 

QueryParameterBinding

locateBinding(Parameter

parameter) { if ( parameter instanceof QueryParameterImplementor ) { //noinspection unchecked return locateBinding( (QueryParameterImplementor) parameter ); } else if ( parameter.getName() != null ) { return locateBinding( parameter.getName() ); } else if ( parameter.getPosition() != null ) { return locateBinding( parameter.getPosition() ); } throw getSession().getExceptionConverter().convert( new IllegalArgumentException( "Could not resolve binding for given parameter reference [" + parameter + "]" ) ); } @SuppressWarnings("WeakerAccess") protected

QueryParameterBinding

locateBinding(QueryParameterImplementor

parameter) { //noinspection unchecked return getQueryParameterBindings().getBinding( parameter ); } @SuppressWarnings("WeakerAccess") protected

QueryParameterBinding

locateBinding(String name) { //noinspection unchecked return (QueryParameterBinding) getQueryParameterBindings().getBinding( name ); } @SuppressWarnings("WeakerAccess") protected

QueryParameterBinding

locateBinding(int position) { //noinspection unchecked return (QueryParameterBinding) getQueryParameterBindings().getBinding( position ); } @Override public QueryImplementor setParameter(Parameter param, Instant value, TemporalType temporalType) { locateBinding( param ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(Parameter param, LocalDateTime value, TemporalType temporalType) { locateBinding( param ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(Parameter param, ZonedDateTime value, TemporalType temporalType) { locateBinding( param ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(Parameter param, OffsetDateTime value, TemporalType temporalType) { locateBinding( param ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, Instant value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, LocalDateTime value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, ZonedDateTime value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, OffsetDateTime value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, Instant value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, LocalDateTime value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, ZonedDateTime value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, OffsetDateTime value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public

QueryImplementor setParameter(QueryParameter

parameter, P value) { locateBinding( parameter ).setBindValue( value ); return this; } @Override public

QueryImplementor setParameter(Parameter

parameter, P value) { if ( value instanceof TypedParameterValue ) { setParameter( parameter, ( (TypedParameterValue) value ).getValue(), ( (TypedParameterValue) value ).getType() ); } else { locateBinding( parameter ).setBindValue( value ); } return this; } @SuppressWarnings("unchecked") private

void setParameter(Parameter

parameter, Object value, AllowableParameterType type) { if ( parameter instanceof QueryParameter ) { setParameter( (QueryParameter) parameter, value, type ); } else if ( value == null ) { locateBinding( parameter ).setBindValue( null, type ); } else if ( value instanceof Collection ) { locateBinding( parameter ).setBindValues( (Collection) value ); } else { locateBinding( parameter ).setBindValue( (P) value, type ); } } @Override public QueryImplementor setParameter(String name, Object value) { if ( value instanceof TypedParameterValue ) { final TypedParameterValue typedValueWrapper = (TypedParameterValue) value; setParameter( name, typedValueWrapper.getValue(), typedValueWrapper.getType() ); } else if ( value instanceof Collection ) { setParameterList( name, (Collection) value ); } else { locateBinding( name ).setBindValue( value ); } return this; } @Override public QueryImplementor setParameter(int position, Object value) { if ( value instanceof TypedParameterValue ) { final TypedParameterValue typedParameterValue = (TypedParameterValue) value; setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() ); } if ( value instanceof Collection ) { setParameterList( Integer.toString( position ), (Collection) value ); } else { locateBinding( position ).setBindValue( value ); } return this; } @Override @SuppressWarnings("unchecked") public

QueryImplementor setParameter(QueryParameter

parameter, P value, AllowableParameterType type) { locateBinding( parameter ).setBindValue( value, type ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameter(String name, Object value, AllowableParameterType type) { locateBinding( name ).setBindValue( value, type ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameter(int position, Object value, AllowableParameterType type) { locateBinding( position ).setBindValue( value, type ); return this; } @Override public

QueryImplementor setParameter(QueryParameter

parameter, P value, TemporalType temporalType) { locateBinding( parameter ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, Object value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, Object value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public

QueryImplementor setParameterList(QueryParameter

parameter, Collection

values) { locateBinding( parameter ).setBindValues( values ); return this; } @SuppressWarnings("unchecked") @Override public QueryImplementor setParameterList(String name, Collection values) { locateBinding( name ).setBindValues( values ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(int position, Collection values) { locateBinding( position ).setBindValues( values ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(String name, Collection values, AllowableParameterType type) { locateBinding( name ).setBindValues( values, type ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(int position, Collection values, AllowableParameterType type) { locateBinding( position ).setBindValues( values, type ); return this; } @Override public QueryImplementor setParameterList(String name, Object[] values) { locateBinding( name ).setBindValues( Arrays.asList( values ) ); return this; } @Override public QueryImplementor setParameterList(int position, Object[] values) { locateBinding( position ).setBindValues( Arrays.asList( values ) ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(String name, Object[] values, AllowableParameterType type) { locateBinding( name ).setBindValues( Arrays.asList( values ), type ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(int position, Object[] values, AllowableParameterType type) { locateBinding( position ).setBindValues( Arrays.asList( values ), type ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(String name, Collection values, Class javaType) { final JavaTypeDescriptor javaDescriptor = getSession().getFactory() .getTypeConfiguration() .getJavaTypeDescriptorRegistry() .getDescriptor( javaType ); if ( javaDescriptor == null ) { setParameterList( name, values ); } else { final AllowableParameterType paramType; final BasicType basicType = getSession().getFactory().getTypeConfiguration().standardBasicTypeForJavaType( javaType ); if ( basicType != null ) { paramType = basicType; } else { final ManagedDomainType managedDomainType = getSession().getFactory() .getDomainModel() .getJpaMetamodel() .managedType( javaType ); if ( managedDomainType != null ) { paramType = (AllowableParameterType) managedDomainType; } else { throw new HibernateException( "Unable to determine AllowableParameterType : " + javaType.getName() ); } } setParameterList( name, values, paramType ); } return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameterList(int position, Collection values, Class javaType) { final JavaTypeDescriptor javaDescriptor = getSession().getFactory() .getTypeConfiguration() .getJavaTypeDescriptorRegistry() .getDescriptor( javaType ); if ( javaDescriptor == null ) { setParameterList( position, values ); } else { final AllowableParameterType paramType; final BasicType basicType = getSession().getFactory().getTypeConfiguration().standardBasicTypeForJavaType( javaType ); if ( basicType != null ) { paramType = basicType; } else { final ManagedDomainType managedDomainType = getSession().getFactory() .getDomainModel() .getJpaMetamodel() .managedType( javaType ); if ( managedDomainType != null ) { paramType = (AllowableParameterType) managedDomainType; } else { throw new HibernateException( "Unable to determine AllowableParameterType : " + javaType.getName() ); } } setParameterList( position, values, paramType ); } return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameter(Parameter param, Calendar value, TemporalType temporalType) { locateBinding( (QueryParameter) param ).setBindValue( value, temporalType ); return this; } @Override @SuppressWarnings("unchecked") public QueryImplementor setParameter(Parameter param, Date value, TemporalType temporalType) { locateBinding( (QueryParameter) param ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, Calendar value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(String name, Date value, TemporalType temporalType) { locateBinding( name ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, Calendar value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override public QueryImplementor setParameter(int position, Date value, TemporalType temporalType) { locateBinding( position ).setBindValue( value, temporalType ); return this; } @Override @SuppressWarnings("unchecked") public T getParameterValue(Parameter param) { final QueryParameterImplementor qp = getParameterMetadata().resolve( param ); if ( qp == null ) { throw new IllegalArgumentException( "The parameter [" + param + "] is not part of this Query" ); } final QueryParameterBinding binding = getQueryParameterBindings().getBinding( qp ); if ( binding == null || !binding.isBound() ) { throw new IllegalStateException( "The parameter [" + param + "] has not yet been bound" ); } if ( binding.isMultiValued() ) { return (T) binding.getBindValues(); } else { return (T) binding.getBindValue(); } } @Override public Object getParameterValue(String name) { final QueryParameterImplementor qp = getParameterMetadata().getQueryParameter( name ); if ( qp == null ) { throw new IllegalArgumentException( "The parameter [" + name + "] is not part of this Query" ); } final QueryParameterBinding binding = getQueryParameterBindings().getBinding( qp ); if ( binding == null || !binding.isBound() ) { throw new IllegalStateException( "The parameter [" + name + "] has not yet been bound" ); } if ( binding.isMultiValued() ) { return binding.getBindValues(); } else { return binding.getBindValue(); } } @Override public Object getParameterValue(int position) { final QueryParameterImplementor qp = getParameterMetadata().getQueryParameter( position ); if ( qp == null ) { throw new IllegalArgumentException( "The parameter [" + position + "] is not part of this Query" ); } final QueryParameterBinding binding = getQueryParameterBindings().getBinding( qp ); if ( binding == null || !binding.isBound() ) { throw new IllegalStateException( "The parameter [" + position + "] has not yet been bound" ); } if ( binding.isMultiValued() ) { return binding.getBindValues(); } else { return binding.getBindValue(); } } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // execution private FlushMode sessionFlushMode; private CacheMode sessionCacheMode; protected void beforeQuery(boolean requiresTxn) { getQueryParameterBindings().validate(); getSession().prepareForQueryExecution( requiresTxn ); prepareForExecution(); assert sessionFlushMode == null; assert sessionCacheMode == null; final FlushMode effectiveFlushMode = getHibernateFlushMode(); if ( effectiveFlushMode != null ) { sessionFlushMode = getSession().getHibernateFlushMode(); getSession().setHibernateFlushMode( effectiveFlushMode ); } final CacheMode effectiveCacheMode = getCacheMode(); if ( effectiveCacheMode != null ) { sessionCacheMode = getSession().getCacheMode(); getSession().setCacheMode( effectiveCacheMode ); } } protected void prepareForExecution() { } @Override public QueryImplementor setProperties(Object bean) { Class clazz = bean.getClass(); for ( String paramName : getParameterMetadata().getNamedParameterNames() ) { try { final PropertyAccess propertyAccess = BuiltInPropertyAccessStrategies.BASIC.getStrategy().buildPropertyAccess( clazz, paramName ); final Getter getter = propertyAccess.getGetter(); final Class retType = getter.getReturnType(); final Object object = getter.get( bean ); if ( Collection.class.isAssignableFrom( retType ) ) { setParameterList( paramName, (Collection) object ); } else if ( retType.isArray() ) { setParameterList( paramName, (Object[]) object ); } else { AllowableParameterType type = determineType( paramName, retType ); setParameter( paramName, object, type ); } } catch (PropertyNotFoundException pnfe) { // ignore } } return this; } @SuppressWarnings("WeakerAccess") protected AllowableParameterType determineType(String namedParam, Class retType) { AllowableParameterType type = locateBinding( namedParam ).getBindType(); if ( type == null ) { type = getParameterMetadata().getQueryParameter( namedParam ).getHibernateType(); } if ( type == null ) { type = getSession().getFactory().resolveParameterBindType( retType ); } return type; } @Override @SuppressWarnings("unchecked") public QueryImplementor setProperties(Map map) { for ( String paramName : getParameterMetadata().getNamedParameterNames() ) { final Object object = map.get( paramName ); if ( object == null ) { if ( map.containsKey( paramName ) ) { setParameter( paramName, null, determineType( paramName, null ) ); } } else { Class retType = object.getClass(); if ( Collection.class.isAssignableFrom( retType ) ) { setParameterList( paramName, (Collection) object ); } else if ( retType.isArray() ) { setParameterList( paramName, (Object[]) object ); } else { setParameter( paramName, object, determineType( paramName, retType ) ); } } } return this; } @SuppressWarnings("WeakerAccess") protected void afterQuery() { if ( sessionFlushMode != null ) { getSession().setHibernateFlushMode( sessionFlushMode ); sessionFlushMode = null; } if ( sessionCacheMode != null ) { getSession().setCacheMode( sessionCacheMode ); sessionCacheMode = null; } } @Override public List list() { beforeQuery( false ); try { return doList(); } catch (IllegalQueryOperationException e) { throw new IllegalStateException( e ); } catch (TypeMismatchException e) { throw new IllegalArgumentException( e ); } catch (HibernateException he) { throw getSession().getExceptionConverter().convert( he ); } finally { afterQuery(); } } protected abstract List doList(); @Override public R uniqueResult() { return uniqueElement( list() ); } @Override public R getSingleResult() { try { final List list = list(); if ( list.size() == 0 ) { throw new NoResultException( "No entity found for query" ); } return uniqueElement( list ); } catch ( HibernateException e ) { if ( getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap() ) { throw getSession().getExceptionConverter().convert( e ); } else { throw e; } } } @SuppressWarnings("WeakerAccess") public static R uniqueElement(List list) throws NonUniqueResultException { int size = list.size(); if ( size == 0 ) { return null; } R first = list.get( 0 ); // todo (6.0) : add a setting here to control whether to perform this validation or not for ( int i = 1; i < size; i++ ) { if ( list.get( i ) != first ) { throw new NonUniqueResultException( list.size() ); } } return first; } @Override public Optional uniqueResultOptional() { return Optional.ofNullable( uniqueResult() ); } @Override public ScrollableResultsImplementor scroll() { return scroll( getSession().getFactory().getJdbcServices().getJdbcEnvironment().getDialect().defaultScrollMode() ); } @Override public ScrollableResultsImplementor scroll(ScrollMode scrollMode) { beforeQuery( false ); try { return doScroll( scrollMode ); } finally { afterQuery(); } } protected abstract ScrollableResultsImplementor doScroll(ScrollMode scrollMode); @Override @SuppressWarnings("unchecked") public Stream stream() { final ScrollableResultsImplementor scrollableResults = scroll( ScrollMode.FORWARD_ONLY ); final ScrollableResultsIterator iterator = new ScrollableResultsIterator<>( scrollableResults ); final Spliterator spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL ); final Stream stream = StreamSupport.stream( spliterator, false ); return stream.onClose( scrollableResults::close ); } @Override public int executeUpdate() throws HibernateException { if ( !getSession().isTransactionInProgress() ) { throw getSession().getExceptionConverter().convert( new TransactionRequiredException( "Executing an update/delete query" ) ); } beforeQuery( true ); try { return doExecuteUpdate(); } catch (IllegalQueryOperationException e) { throw new IllegalStateException( e ); } catch( TypeMismatchException e ) { throw new IllegalArgumentException( e ); } catch ( HibernateException e) { if ( getSession().getFactory().getSessionFactoryOptions().isJpaBootstrap() ) { throw getSession().getExceptionConverter().convert( e ); } else { throw e; } } finally { afterQuery(); } } protected abstract int doExecuteUpdate(); @Override public void setOptionalId(Serializable id) { throw new UnsupportedOperationException( "Not sure yet how to handle this in SQM based queries, but for sure it will be different" ); } @Override public void setOptionalEntityName(String entityName) { throw new UnsupportedOperationException( "Not sure yet how to handle this in SQM based queries, but for sure it will be different" ); } @Override public void setOptionalObject(Object optionalObject) { throw new UnsupportedOperationException( "Not sure yet how to handle this in SQM based queries, but for sure it will be different" ); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy