alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Hibernate example source code file (CustomLoader.java)

This example Hibernate source code file (CustomLoader.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Hibernate tags/keywords

arraylist, hibernateexception, hibernateexception, jdbc, list, list, object, object, override, override, queryable, resultset, sql, sqlexception, string, type, util

The Hibernate CustomLoader.java source code

/*
 * Hibernate, Relational Persistence for Idiomatic Java
 *
 * Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
 * indicated by the @author tags or express copyright attribution
 * statements applied by the authors.  All third-party contributions are
 * distributed under license by Red Hat Middleware LLC.
 *
 * This copyrighted material is made available to anyone wishing to use, modify,
 * copy, or redistribute it subject to the terms and conditions of the GNU
 * Lesser General Public License, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License
 * for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this distribution; if not, write to:
 * Free Software Foundation, Inc.
 * 51 Franklin Street, Fifth Floor
 * Boston, MA  02110-1301  USA
 *
 */
package org.hibernate.loader.custom;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.QueryException;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.hql.internal.HolderInstantiator;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.loader.CollectionAliases;
import org.hibernate.loader.EntityAliases;
import org.hibernate.loader.Loader;
import org.hibernate.persister.collection.CollectionPersister;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;


/**
 * Extension point for loaders which use a SQL result set with "unexpected" column aliases.
 *
 * @author Gavin King
 * @author Steve Ebersole
 */
public class CustomLoader extends Loader {

	// Currently *not* cachable if autodiscover types is in effect (e.g. "select * ...")

	private final String sql;
	private final Set querySpaces = new HashSet();
	private final Map namedParameterBindPoints;

	private final Queryable[] entityPersisters;
	private final int[] entiytOwners;
	private final EntityAliases[] entityAliases;

	private final QueryableCollection[] collectionPersisters;
	private final int[] collectionOwners;
	private final CollectionAliases[] collectionAliases;

	private final LockMode[] lockModes;

	private boolean[] includeInResultRow;

//	private final String[] sqlAliases;
//	private final String[] sqlAliasSuffixes;
	private final ResultRowProcessor rowProcessor;

	// this is only needed (afaict) for processing results from the query cache;
	// however, this cannot possibly work in the case of discovered types...
	private Type[] resultTypes;

	// this is only needed (afaict) for ResultTransformer processing...
	private String[] transformerAliases;

	public CustomLoader(CustomQuery customQuery, SessionFactoryImplementor factory) {
		super( factory );

		this.sql = customQuery.getSQL();
		this.querySpaces.addAll( customQuery.getQuerySpaces() );
		this.namedParameterBindPoints = customQuery.getNamedParameterBindPoints();

		List entityPersisters = new ArrayList();
		List entityOwners = new ArrayList();
		List entityAliases = new ArrayList();

		List collectionPersisters = new ArrayList();
		List collectionOwners = new ArrayList();
		List collectionAliases = new ArrayList();

		List lockModes = new ArrayList();
		List resultColumnProcessors = new ArrayList();
		List nonScalarReturnList = new ArrayList();
		List resultTypes = new ArrayList();
		List specifiedAliases = new ArrayList();
		int returnableCounter = 0;
		boolean hasScalars = false;

		List includeInResultRowList = new ArrayList();

		Iterator itr = customQuery.getCustomQueryReturns().iterator();
		while ( itr.hasNext() ) {
			final Return rtn = ( Return ) itr.next();
			if ( rtn instanceof ScalarReturn ) {
				ScalarReturn scalarRtn = ( ScalarReturn ) rtn;
				resultTypes.add( scalarRtn.getType() );
				specifiedAliases.add( scalarRtn.getColumnAlias() );
				resultColumnProcessors.add(
						new ScalarResultColumnProcessor(
								StringHelper.unquote( scalarRtn.getColumnAlias(), factory.getDialect() ),
								scalarRtn.getType()
						)
				);
				includeInResultRowList.add( true );
				hasScalars = true;
			}
			else if ( rtn instanceof RootReturn ) {
				RootReturn rootRtn = ( RootReturn ) rtn;
				Queryable persister = ( Queryable ) factory.getEntityPersister( rootRtn.getEntityName() );
				entityPersisters.add( persister );
				lockModes.add( (rootRtn.getLockMode()) );
				resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
				nonScalarReturnList.add( rtn );
				entityOwners.add( -1 );
				resultTypes.add( persister.getType() );
				specifiedAliases.add( rootRtn.getAlias() );
				entityAliases.add( rootRtn.getEntityAliases() );
				ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
				includeInResultRowList.add( true );
			}
			else if ( rtn instanceof CollectionReturn ) {
				CollectionReturn collRtn = ( CollectionReturn ) rtn;
				String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
				QueryableCollection persister = ( QueryableCollection ) factory.getCollectionPersister( role );
				collectionPersisters.add( persister );
				lockModes.add( collRtn.getLockMode() );
				resultColumnProcessors.add( new NonScalarResultColumnProcessor( returnableCounter++ ) );
				nonScalarReturnList.add( rtn );
				collectionOwners.add( -1 );
				resultTypes.add( persister.getType() );
				specifiedAliases.add( collRtn.getAlias() );
				collectionAliases.add( collRtn.getCollectionAliases() );
				// determine if the collection elements are entities...
				Type elementType = persister.getElementType();
				if ( elementType.isEntityType() ) {
					Queryable elementPersister = ( Queryable ) ( ( EntityType ) elementType ).getAssociatedJoinable( factory );
					entityPersisters.add( elementPersister );
					entityOwners.add( -1 );
					entityAliases.add( collRtn.getElementEntityAliases() );
					ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
				}
				includeInResultRowList.add( true );
			}
			else if ( rtn instanceof EntityFetchReturn ) {
				EntityFetchReturn fetchRtn = ( EntityFetchReturn ) rtn;
				NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
				int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
				entityOwners.add( ownerIndex );
				lockModes.add( fetchRtn.getLockMode() );
				Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
				EntityType fetchedType = ( EntityType ) ownerPersister.getPropertyType( fetchRtn.getOwnerProperty() );
				String entityName = fetchedType.getAssociatedEntityName( getFactory() );
				Queryable persister = ( Queryable ) factory.getEntityPersister( entityName );
				entityPersisters.add( persister );
				nonScalarReturnList.add( rtn );
				specifiedAliases.add( fetchRtn.getAlias() );
				entityAliases.add( fetchRtn.getEntityAliases() );
				ArrayHelper.addAll( querySpaces, persister.getQuerySpaces() );
				includeInResultRowList.add( false );
			}
			else if ( rtn instanceof CollectionFetchReturn ) {
				CollectionFetchReturn fetchRtn = ( CollectionFetchReturn ) rtn;
				NonScalarReturn ownerDescriptor = fetchRtn.getOwner();
				int ownerIndex = nonScalarReturnList.indexOf( ownerDescriptor );
				collectionOwners.add( ownerIndex );
				lockModes.add( fetchRtn.getLockMode() );
				Queryable ownerPersister = determineAppropriateOwnerPersister( ownerDescriptor );
				String role = ownerPersister.getEntityName() + '.' + fetchRtn.getOwnerProperty();
				QueryableCollection persister = ( QueryableCollection ) factory.getCollectionPersister( role );
				collectionPersisters.add( persister );
				nonScalarReturnList.add( rtn );
				specifiedAliases.add( fetchRtn.getAlias() );
				collectionAliases.add( fetchRtn.getCollectionAliases() );
				// determine if the collection elements are entities...
				Type elementType = persister.getElementType();
				if ( elementType.isEntityType() ) {
					Queryable elementPersister = ( Queryable ) ( ( EntityType ) elementType ).getAssociatedJoinable( factory );
					entityPersisters.add( elementPersister );
					entityOwners.add( ownerIndex );
					entityAliases.add( fetchRtn.getElementEntityAliases() );
					ArrayHelper.addAll( querySpaces, elementPersister.getQuerySpaces() );
				}
				includeInResultRowList.add( false );
			}
			else {
				throw new HibernateException( "unexpected custom query return type : " + rtn.getClass().getName() );
			}
		}

		this.entityPersisters = new Queryable[ entityPersisters.size() ];
		for ( int i = 0; i < entityPersisters.size(); i++ ) {
			this.entityPersisters[i] = ( Queryable ) entityPersisters.get( i );
		}
		this.entiytOwners = ArrayHelper.toIntArray( entityOwners );
		this.entityAliases = new EntityAliases[ entityAliases.size() ];
		for ( int i = 0; i < entityAliases.size(); i++ ) {
			this.entityAliases[i] = ( EntityAliases ) entityAliases.get( i );
		}

		this.collectionPersisters = new QueryableCollection[ collectionPersisters.size() ];
		for ( int i = 0; i < collectionPersisters.size(); i++ ) {
			this.collectionPersisters[i] = ( QueryableCollection ) collectionPersisters.get( i );
		}
		this.collectionOwners = ArrayHelper.toIntArray( collectionOwners );
		this.collectionAliases = new CollectionAliases[ collectionAliases.size() ];
		for ( int i = 0; i < collectionAliases.size(); i++ ) {
			this.collectionAliases[i] = ( CollectionAliases ) collectionAliases.get( i );
		}

		this.lockModes = new LockMode[ lockModes.size() ];
		for ( int i = 0; i < lockModes.size(); i++ ) {
			this.lockModes[i] = ( LockMode ) lockModes.get( i );
		}

		this.resultTypes = ArrayHelper.toTypeArray( resultTypes );
		this.transformerAliases = ArrayHelper.toStringArray( specifiedAliases );

		this.rowProcessor = new ResultRowProcessor(
				hasScalars,
		        ( ResultColumnProcessor[] ) resultColumnProcessors.toArray( new ResultColumnProcessor[ resultColumnProcessors.size() ] )
		);

		this.includeInResultRow = ArrayHelper.toBooleanArray( includeInResultRowList );
	}

	private Queryable determineAppropriateOwnerPersister(NonScalarReturn ownerDescriptor) {
		String entityName = null;
		if ( ownerDescriptor instanceof RootReturn ) {
			entityName = ( ( RootReturn ) ownerDescriptor ).getEntityName();
		}
		else if ( ownerDescriptor instanceof CollectionReturn ) {
			CollectionReturn collRtn = ( CollectionReturn ) ownerDescriptor;
			String role = collRtn.getOwnerEntityName() + "." + collRtn.getOwnerProperty();
			CollectionPersister persister = getFactory().getCollectionPersister( role );
			EntityType ownerType = ( EntityType ) persister.getElementType();
			entityName = ownerType.getAssociatedEntityName( getFactory() );
		}
		else if ( ownerDescriptor instanceof FetchReturn ) {
			FetchReturn fetchRtn = ( FetchReturn ) ownerDescriptor;
			Queryable persister = determineAppropriateOwnerPersister( fetchRtn.getOwner() );
			Type ownerType = persister.getPropertyType( fetchRtn.getOwnerProperty() );
			if ( ownerType.isEntityType() ) {
				entityName = ( ( EntityType ) ownerType ).getAssociatedEntityName( getFactory() );
			}
			else if ( ownerType.isCollectionType() ) {
				Type ownerCollectionElementType = ( ( CollectionType ) ownerType ).getElementType( getFactory() );
				if ( ownerCollectionElementType.isEntityType() ) {
					entityName = ( ( EntityType ) ownerCollectionElementType ).getAssociatedEntityName( getFactory() );
				}
			}
		}

		if ( entityName == null ) {
			throw new HibernateException( "Could not determine fetch owner : " + ownerDescriptor );
		}

		return ( Queryable ) getFactory().getEntityPersister( entityName );
	}

	@Override
    protected String getQueryIdentifier() {
		return sql;
	}

	@Override
    protected String getSQLString() {
		return sql;
	}

	public Set getQuerySpaces() {
		return querySpaces;
	}

	@Override
    protected LockMode[] getLockModes(LockOptions lockOptions) {
		return lockModes;
	}

	@Override
    protected Loadable[] getEntityPersisters() {
		return entityPersisters;
	}

	@Override
    protected CollectionPersister[] getCollectionPersisters() {
		return collectionPersisters;
	}

	@Override
    protected int[] getCollectionOwners() {
		return collectionOwners;
	}

	@Override
    protected int[] getOwners() {
		return entiytOwners;
	}

	public List list(SessionImplementor session, QueryParameters queryParameters) throws HibernateException {
		return list( session, queryParameters, querySpaces, resultTypes );
	}

	public ScrollableResults scroll(
			final QueryParameters queryParameters,
			final SessionImplementor session) throws HibernateException {
		return scroll(
				queryParameters,
				resultTypes,
				getHolderInstantiator( queryParameters.getResultTransformer(), getReturnAliasesForTransformer() ),
				session
		);
	}

	static private HolderInstantiator getHolderInstantiator(ResultTransformer resultTransformer, String[] queryReturnAliases) {
		if ( resultTransformer == null ) {
			return HolderInstantiator.NOOP_INSTANTIATOR;
		}
		else {
			return new HolderInstantiator(resultTransformer, queryReturnAliases);
		}
	}

	@Override
    protected String[] getResultRowAliases() {
		return transformerAliases;
	}

	@Override
    protected ResultTransformer resolveResultTransformer(ResultTransformer resultTransformer) {
		return HolderInstantiator.resolveResultTransformer( null, resultTransformer );
	}

	@Override
    protected boolean[] includeInResultRow() {
		return includeInResultRow;
	}

	@Override
    protected Object getResultColumnOrRow(
			Object[] row,
	        ResultTransformer transformer,
	        ResultSet rs,
	        SessionImplementor session) throws SQLException, HibernateException {
		return rowProcessor.buildResultRow( row, rs, transformer != null, session );
	}

	@Override
    protected Object[] getResultRow(Object[] row, ResultSet rs, SessionImplementor session)
			throws SQLException, HibernateException {
		return rowProcessor.buildResultRow( row, rs, session );
	}

	@Override
    protected List getResultList(List results, ResultTransformer resultTransformer) throws QueryException {
		// meant to handle dynamic instantiation queries...(Copy from QueryLoader)
		HolderInstantiator holderInstantiator = HolderInstantiator.getHolderInstantiator(
				null,
				resultTransformer,
				getReturnAliasesForTransformer()
		);
		if ( holderInstantiator.isRequired() ) {
			for ( int i = 0; i < results.size(); i++ ) {
				Object[] row = ( Object[] ) results.get( i );
				Object result = holderInstantiator.instantiate(row);
				results.set( i, result );
			}

			return resultTransformer.transformList(results);
		}
		else {
			return results;
		}
	}

	private String[] getReturnAliasesForTransformer() {
		return transformerAliases;
	}

	@Override
    protected EntityAliases[] getEntityAliases() {
		return entityAliases;
	}

	@Override
    protected CollectionAliases[] getCollectionAliases() {
		return collectionAliases;
	}

	@Override
    public int[] getNamedParameterLocs(String name) throws QueryException {
		Object loc = namedParameterBindPoints.get( name );
		if ( loc == null ) {
			throw new QueryException(
					"Named parameter does not appear in Query: " + name,
					sql
			);
		}
		if ( loc instanceof Integer ) {
			return new int[] { ( ( Integer ) loc ).intValue() };
		}
		else {
			return ArrayHelper.toIntArray( ( List ) loc );
		}
	}


	public class ResultRowProcessor {
		private final boolean hasScalars;
		private ResultColumnProcessor[] columnProcessors;

		public ResultRowProcessor(boolean hasScalars, ResultColumnProcessor[] columnProcessors) {
			this.hasScalars = hasScalars || ( columnProcessors == null || columnProcessors.length == 0 );
			this.columnProcessors = columnProcessors;
		}

		public void prepareForAutoDiscovery(Metadata metadata) throws SQLException {
			if ( columnProcessors == null || columnProcessors.length == 0 ) {
				int columns = metadata.getColumnCount();
				columnProcessors = new ResultColumnProcessor[ columns ];
				for ( int i = 1; i <= columns; i++ ) {
					columnProcessors[ i - 1 ] = new ScalarResultColumnProcessor( i );
				}

			}
		}

		/**
		 * Build a logical result row.
		 * <p/>
		 * At this point, Loader has already processed all non-scalar result data.  We
		 * just need to account for scalar result data here...
		 *
		 * @param data Entity data defined as "root returns" and already handled by the
		 * normal Loader mechanism.
		 * @param resultSet The JDBC result set (positioned at the row currently being processed).
		 * @param hasTransformer Does this query have an associated {@link ResultTransformer}
		 * @param session The session from which the query request originated.
		 * @return The logical result row
		 * @throws SQLException
		 * @throws HibernateException
		 */
		public Object buildResultRow(
				Object[] data,
				ResultSet resultSet,
				boolean hasTransformer,
				SessionImplementor session) throws SQLException, HibernateException {
			Object[] resultRow = buildResultRow( data, resultSet, session );
			return ( hasTransformer )
			       ? resultRow
			       : ( resultRow.length == 1 )
			         ? resultRow[0]
			         : resultRow;
		}
		public Object[] buildResultRow(
				Object[] data,
				ResultSet resultSet,
				SessionImplementor session) throws SQLException, HibernateException {
			Object[] resultRow;
			if ( !hasScalars ) {
				resultRow = data;
			}
			else {
				// build an array with indices equal to the total number
				// of actual returns in the result Hibernate will return
				// for this query (scalars + non-scalars)
				resultRow = new Object[ columnProcessors.length ];
				for ( int i = 0; i < columnProcessors.length; i++ ) {
					resultRow[i] = columnProcessors[i].extract( data, resultSet, session );
				}
			}

			return resultRow;
		}
	}

	private static interface ResultColumnProcessor {
		public Object extract(Object[] data, ResultSet resultSet, SessionImplementor session) throws SQLException, HibernateException;
		public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException, HibernateException;
	}

	public class NonScalarResultColumnProcessor implements ResultColumnProcessor {
		private final int position;

		public NonScalarResultColumnProcessor(int position) {
			this.position = position;
		}

		public Object extract(
				Object[] data,
				ResultSet resultSet,
				SessionImplementor session) throws SQLException, HibernateException {
			return data[ position ];
		}

		public void performDiscovery(Metadata metadata, List types, List aliases) {
		}

	}

	public class ScalarResultColumnProcessor implements ResultColumnProcessor {
		private int position = -1;
		private String alias;
		private Type type;

		public ScalarResultColumnProcessor(int position) {
			this.position = position;
		}

		public ScalarResultColumnProcessor(String alias, Type type) {
			this.alias = alias;
			this.type = type;
		}

		public Object extract(
				Object[] data,
				ResultSet resultSet,
				SessionImplementor session) throws SQLException, HibernateException {
			return type.nullSafeGet( resultSet, alias, session, null );
		}

		public void performDiscovery(Metadata metadata, List types, List aliases) throws SQLException {
			if ( alias == null ) {
				alias = metadata.getColumnName( position );
			}
			else if ( position < 0 ) {
				position = metadata.resolveColumnPosition( alias );
			}
			if ( type == null ) {
				type = metadata.getHibernateType( position );
			}
			types.add( type );
			aliases.add( alias );
		}
	}

	@Override
    protected void autoDiscoverTypes(ResultSet rs) {
		try {
			Metadata metadata = new Metadata( getFactory(), rs );
			List aliases = new ArrayList();
			List types = new ArrayList();

			rowProcessor.prepareForAutoDiscovery( metadata );

			for ( int i = 0; i < rowProcessor.columnProcessors.length; i++ ) {
				rowProcessor.columnProcessors[i].performDiscovery( metadata, types, aliases );
			}

			resultTypes = ArrayHelper.toTypeArray( types );
			transformerAliases = ArrayHelper.toStringArray( aliases );
		}
		catch ( SQLException e ) {
			throw new HibernateException( "Exception while trying to autodiscover types.", e );
		}
	}

	private static class Metadata {
		private final SessionFactoryImplementor factory;
		private final ResultSet resultSet;
		private final ResultSetMetaData resultSetMetaData;

		public Metadata(SessionFactoryImplementor factory, ResultSet resultSet) throws HibernateException {
			try {
				this.factory = factory;
				this.resultSet = resultSet;
				this.resultSetMetaData = resultSet.getMetaData();
			}
			catch( SQLException e ) {
				throw new HibernateException( "Could not extract result set metadata", e );
			}
		}

		public int getColumnCount() throws HibernateException {
			try {
				return resultSetMetaData.getColumnCount();
			}
			catch( SQLException e ) {
				throw new HibernateException( "Could not determine result set column count", e );
			}
		}

		public int resolveColumnPosition(String columnName) throws HibernateException {
			try {
				return resultSet.findColumn( columnName );
			}
			catch( SQLException e ) {
				throw new HibernateException( "Could not resolve column name in result set [" + columnName + "]", e );
			}
		}

		public String getColumnName(int position) throws HibernateException {
			try {
				return factory.getDialect().getColumnAliasExtractor().extractColumnAlias( resultSetMetaData, position );
			}
			catch( SQLException e ) {
				throw new HibernateException( "Could not resolve column name [" + position + "]", e );
			}
		}

		public Type getHibernateType(int columnPos) throws SQLException {
			int columnType = resultSetMetaData.getColumnType( columnPos );
			int scale = resultSetMetaData.getScale( columnPos );
			int precision = resultSetMetaData.getPrecision( columnPos );
			return factory.getTypeResolver().heuristicType(
					factory.getDialect().getHibernateTypeName(
							columnType,
							precision,
							precision,
							scale
					)
			);
		}
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate CustomLoader.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.