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

Hibernate example source code file (FromElementType.java)

This example Hibernate source code file (FromElementType.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

entitypersister, fromelementtype, joinable, propertymapping, queryable, queryable, queryablecollection, queryexception, queryexception, string, string, stringbuffer, type, type, util

The Hibernate FromElementType.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.hql.internal.ast.tree;

import java.util.List;
import java.util.Map;

import org.hibernate.engine.internal.JoinSequence;
import org.hibernate.hql.internal.CollectionProperties;
import org.hibernate.hql.internal.CollectionSubqueryFactory;
import org.hibernate.hql.internal.NameGenerator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.MappingException;
import org.hibernate.QueryException;
import org.hibernate.hql.internal.antlr.HqlSqlTokenTypes;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.param.ParameterSpecification;
import org.hibernate.persister.collection.CollectionPropertyMapping;
import org.hibernate.persister.collection.CollectionPropertyNames;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Joinable;
import org.hibernate.persister.entity.PropertyMapping;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.jboss.logging.Logger;

/**
 * Delegate that handles the type and join sequence information for a FromElement.
 *
 * @author josh
 */
class FromElementType {

    private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, FromElementType.class.getName());

	private FromElement fromElement;
	private EntityType entityType;
	private EntityPersister persister;
	private QueryableCollection queryableCollection;
	private CollectionPropertyMapping collectionPropertyMapping;
	private JoinSequence joinSequence;
	private String collectionSuffix;
	private ParameterSpecification indexCollectionSelectorParamSpec;

	public FromElementType(FromElement fromElement, EntityPersister persister, EntityType entityType) {
		this.fromElement = fromElement;
		this.persister = persister;
		this.entityType = entityType;
		if ( persister != null ) {
			fromElement.setText( ( ( Queryable ) persister ).getTableName() + " " + getTableAlias() );
		}
	}

	protected FromElementType(FromElement fromElement) {
		this.fromElement = fromElement;
	}

	private String getTableAlias() {
		return fromElement.getTableAlias();
	}

	private String getCollectionTableAlias() {
		return fromElement.getCollectionTableAlias();
	}

	public String getCollectionSuffix() {
		return collectionSuffix;
	}

	public void setCollectionSuffix(String suffix) {
		collectionSuffix = suffix;
	}

	public EntityPersister getEntityPersister() {
		return persister;
	}

	public Type getDataType() {
		if ( persister == null ) {
			if ( queryableCollection == null ) {
				return null;
			}
			return queryableCollection.getType();
		}
		else {
			return entityType;
		}
	}

	public Type getSelectType() {
		if (entityType==null) return null;
		boolean shallow = fromElement.getFromClause().getWalker().isShallowQuery();
		return fromElement.getSessionFactoryHelper()
				.getFactory()
				.getTypeResolver()
				.getTypeFactory().manyToOne( entityType.getAssociatedEntityName(), shallow );
	}

	/**
	 * Returns the Hibernate queryable implementation for the HQL class.
	 *
	 * @return the Hibernate queryable implementation for the HQL class.
	 */
	public Queryable getQueryable() {
		return ( persister instanceof Queryable ) ? ( Queryable ) persister : null;
	}

	/**
	 * Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).
	 *
	 * @param i the sequence of the returned type
	 * @return the identifier select with the column alias.
	 */
	String renderScalarIdentifierSelect(int i) {
		checkInitialized();
		String[] cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( getTableAlias(), EntityPersister.ENTITY_ID );
		StringBuffer buf = new StringBuffer();
		// For property references generate <tablealias>. as 
		for ( int j = 0; j < cols.length; j++ ) {
			String column = cols[j];
			if ( j > 0 ) {
				buf.append( ", " );
			}
			buf.append( column ).append( " as " ).append( NameGenerator.scalarName( i, j ) );
		}
		return buf.toString();
	}

	/**
	 * Returns the identifier select SQL fragment.
	 *
	 * @param size The total number of returned types.
	 * @param k    The sequence of the current returned type.
	 * @return the identifier select SQL fragment.
	 */
	String renderIdentifierSelect(int size, int k) {
		checkInitialized();
		// Render the identifier select fragment using the table alias.
		if ( fromElement.getFromClause().isSubQuery() ) {
			// TODO: Replace this with a more elegant solution.
			String[] idColumnNames = ( persister != null ) ?
					( ( Queryable ) persister ).getIdentifierColumnNames() : new String[0];
			StringBuffer buf = new StringBuffer();
			for ( int i = 0; i < idColumnNames.length; i++ ) {
				buf.append( fromElement.getTableAlias() ).append( '.' ).append( idColumnNames[i] );
				if ( i != idColumnNames.length - 1 ) buf.append( ", " );
			}
			return buf.toString();
		}
		else {
			if (persister==null) {
				throw new QueryException( "not an entity" );
			}
			String fragment = ( ( Queryable ) persister ).identifierSelectFragment( getTableAlias(), getSuffix( size, k ) );
			return trimLeadingCommaAndSpaces( fragment );
		}
	}

	private String getSuffix(int size, int sequence) {
		return generateSuffix( size, sequence );
	}

	private static String generateSuffix(int size, int k) {
		String suffix = size == 1 ? "" : Integer.toString( k ) + '_';
		return suffix;
	}

	private void checkInitialized() {
		fromElement.checkInitialized();
	}

	/**
	 * Returns the property select SQL fragment.
	 * @param size The total number of returned types.
	 * @param k    The sequence of the current returned type.
	 * @return the property select SQL fragment.
	 */
	String renderPropertySelect(int size, int k, boolean allProperties) {
		checkInitialized();
		if ( persister == null ) {
			return "";
		}
		else {
			String fragment =  ( ( Queryable ) persister ).propertySelectFragment(
					getTableAlias(),
					getSuffix( size, k ),
					allProperties
				);
			return trimLeadingCommaAndSpaces( fragment );
		}
	}

	String renderCollectionSelectFragment(int size, int k) {
		if ( queryableCollection == null ) {
			return "";
		}
		else {
			if ( collectionSuffix == null ) {
				collectionSuffix = generateSuffix( size, k );
			}
			String fragment = queryableCollection.selectFragment( getCollectionTableAlias(), collectionSuffix );
			return trimLeadingCommaAndSpaces( fragment );
		}
	}

	public String renderValueCollectionSelectFragment(int size, int k) {
		if ( queryableCollection == null ) {
			return "";
		}
		else {
			if ( collectionSuffix == null ) {
				collectionSuffix = generateSuffix( size, k );
			}
			String fragment =  queryableCollection.selectFragment( getTableAlias(), collectionSuffix );
			return trimLeadingCommaAndSpaces( fragment );
		}
	}

	/**
	 * This accounts for a quirk in Queryable, where it sometimes generates ',  ' in front of the
	 * SQL fragment.  :-P
	 *
	 * @param fragment An SQL fragment.
	 * @return The fragment, without the leading comma and spaces.
	 */
	private static String trimLeadingCommaAndSpaces(String fragment) {
		if ( fragment.length() > 0 && fragment.charAt( 0 ) == ',' ) {
			fragment = fragment.substring( 1 );
		}
		fragment = fragment.trim();
		return fragment.trim();
	}

	public void setJoinSequence(JoinSequence joinSequence) {
		this.joinSequence = joinSequence;
	}

	public JoinSequence getJoinSequence() {
		if ( joinSequence != null ) {
			return joinSequence;
		}

		// Class names in the FROM clause result in a JoinSequence (the old FromParser does this).
		if ( persister instanceof Joinable ) {
			Joinable joinable = ( Joinable ) persister;
			return fromElement.getSessionFactoryHelper().createJoinSequence().setRoot( joinable, getTableAlias() );
		}
		else {
			return null;	// TODO: Should this really return null?  If not, figure out something better to do here.
		}
	}

	public void setQueryableCollection(QueryableCollection queryableCollection) {
		if ( this.queryableCollection != null ) {
			throw new IllegalStateException( "QueryableCollection is already defined for " + this + "!" );
		}
		this.queryableCollection = queryableCollection;
		if ( !queryableCollection.isOneToMany() ) {
			// For many-to-many joins, use the tablename from the queryable collection for the default text.
			fromElement.setText( queryableCollection.getTableName() + " " + getTableAlias() );
		}
	}

	public QueryableCollection getQueryableCollection() {
		return queryableCollection;
	}

	/**
	 * Returns the type of a property, given it's name (the last part) and the full path.
	 *
	 * @param propertyName The last part of the full path to the property.
	 * @return The type.
	 * @0param propertyPath The full property path.
	 */
	public Type getPropertyType(String propertyName, String propertyPath) {
		checkInitialized();
		Type type = null;
		// If this is an entity and the property is the identifier property, then use getIdentifierType().
		//      Note that the propertyName.equals( propertyPath ) checks whether we have a component
		//      key reference, where the component class property name is the same as the
		//      entity id property name; if the two are not equal, this is the case and
		//      we'd need to "fall through" to using the property mapping.
		if ( persister != null && propertyName.equals( propertyPath ) && propertyName.equals( persister.getIdentifierPropertyName() ) ) {
			type = persister.getIdentifierType();
		}
		else {	// Otherwise, use the property mapping.
			PropertyMapping mapping = getPropertyMapping( propertyName );
			type = mapping.toType( propertyPath );
		}
		if ( type == null ) {
			throw new MappingException( "Property " + propertyName + " does not exist in " +
					( ( queryableCollection == null ) ? "class" : "collection" ) + " "
					+ ( ( queryableCollection == null ) ? fromElement.getClassName() : queryableCollection.getRole() ) );
		}
		return type;
	}

	String[] toColumns(String tableAlias, String path, boolean inSelect) {
		return toColumns( tableAlias, path, inSelect, false );
	}

	String[] toColumns(String tableAlias, String path, boolean inSelect, boolean forceAlias) {
		checkInitialized();
		PropertyMapping propertyMapping = getPropertyMapping( path );
		// If this from element is a collection and the path is a collection property (maxIndex, etc.) then
		// generate a sub-query.
		//
		// NOTE : in the case of this being a collection property in the select, not generating the subquery
		// will not generally work.  The specific cases I am thinking about are the minIndex, maxIndex
		// (most likely minElement, maxElement as well) cases.
		//	todo : if ^^ is the case we should thrown an exception here rather than waiting for the sql error
		//		if the dialect supports select-clause subqueries we could go ahead and generate the subquery also
		if ( !inSelect && queryableCollection != null && CollectionProperties.isCollectionProperty( path ) ) {
			Map enabledFilters = fromElement.getWalker().getEnabledFilters();
			String subquery = CollectionSubqueryFactory.createCollectionSubquery(
					joinSequence.copy().setUseThetaStyle( true ),
					enabledFilters,
					propertyMapping.toColumns( tableAlias, path )
			);
            LOG.debugf("toColumns(%s,%s) : subquery = %s", tableAlias, path, subquery);
			return new String[]{"(" + subquery + ")"};
		}
        if (forceAlias) {
            return propertyMapping.toColumns(tableAlias, path);
        } else if (fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.SELECT) {
            return propertyMapping.toColumns(tableAlias, path);
        } else if (fromElement.getWalker().getCurrentClauseType() == HqlSqlTokenTypes.SELECT) {
            return propertyMapping.toColumns(tableAlias, path);
        } else if (fromElement.getWalker().isSubQuery()) {
            // for a subquery, the alias to use depends on a few things (we
            // already know this is not an overall SELECT):
            // 1) if this FROM_ELEMENT represents a correlation to the
            // outer-most query
            // A) if the outer query represents a multi-table
            // persister, we need to use the given alias
            // in anticipation of one of the multi-table
            // executors being used (as this subquery will
            // actually be used in the "id select" phase
            // of that multi-table executor)
            // B) otherwise, we need to use the persister's
            // table name as the column qualification
            // 2) otherwise (not correlated), use the given alias
            if (isCorrelation()) {
                if (isMultiTable()) return propertyMapping.toColumns(tableAlias, path);
                return propertyMapping.toColumns(extractTableName(), path);
			}
            return propertyMapping.toColumns(tableAlias, path);
        } else {
            String[] columns = propertyMapping.toColumns(path);
            LOG.trace("Using non-qualified column reference [" + path + " -> (" + ArrayHelper.toString(columns) + ")]");
            return columns;
        }
	}

	private boolean isCorrelation() {
		FromClause top = fromElement.getWalker().getFinalFromClause();
		return fromElement.getFromClause() != fromElement.getWalker().getCurrentFromClause() &&
	           fromElement.getFromClause() == top;
	}

	private boolean isMultiTable() {
		// should be safe to only ever expect EntityPersister references here
		return fromElement.getQueryable() != null &&
	           fromElement.getQueryable().isMultiTable();
	}

	private String extractTableName() {
		// should be safe to only ever expect EntityPersister references here
		return fromElement.getQueryable().getTableName();
	}

	private static final List SPECIAL_MANY2MANY_TREATMENT_FUNCTION_NAMES = java.util.Arrays.asList(
			new String[] {
					CollectionPropertyNames.COLLECTION_INDEX,
					CollectionPropertyNames.COLLECTION_MIN_INDEX,
					CollectionPropertyNames.COLLECTION_MAX_INDEX
			}
	);

	PropertyMapping getPropertyMapping(String propertyName) {
		checkInitialized();
		if ( queryableCollection == null ) {		// Not a collection?
			return ( PropertyMapping ) persister;	// Return the entity property mapping.
		}

		// indexed, many-to-many collections must be treated specially here if the property to
		// be mapped touches on the index as we must adjust the alias to use the alias from
		// the association table (which i different than the one passed in
		if ( queryableCollection.isManyToMany()
				&& queryableCollection.hasIndex()
				&& SPECIAL_MANY2MANY_TREATMENT_FUNCTION_NAMES.contains( propertyName ) ) {
			return new SpecialManyToManyCollectionPropertyMapping();
		}

		// If the property is a special collection property name, return a CollectionPropertyMapping.
		if ( CollectionProperties.isCollectionProperty( propertyName ) ) {
			if ( collectionPropertyMapping == null ) {
				collectionPropertyMapping = new CollectionPropertyMapping( queryableCollection );
			}
			return collectionPropertyMapping;
		}

		if ( queryableCollection.getElementType().isAnyType() ) {
			// collection of <many-to-any/> mappings...
			// used to circumvent the component-collection check below...
			return queryableCollection;

		}

		if ( queryableCollection.getElementType().isComponentType() ) {
			// Collection of components.
			if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) {
				return ( PropertyMapping ) queryableCollection.getOwnerEntityPersister();
			}
		}
		return queryableCollection;
	}

	public boolean isCollectionOfValuesOrComponents() {
		return persister == null
				&& queryableCollection != null
				&& !queryableCollection.getElementType().isEntityType();
	}

	public boolean isEntity() {
		return persister != null;
	}

	public ParameterSpecification getIndexCollectionSelectorParamSpec() {
		return indexCollectionSelectorParamSpec;
	}

	public void setIndexCollectionSelectorParamSpec(ParameterSpecification indexCollectionSelectorParamSpec) {
		this.indexCollectionSelectorParamSpec = indexCollectionSelectorParamSpec;
	}

	private class SpecialManyToManyCollectionPropertyMapping implements PropertyMapping {
		/**
		 * {@inheritDoc}
		 */
		public Type getType() {
			return queryableCollection.getCollectionType();
		}

		private void validate(String propertyName) {
			if ( ! ( CollectionPropertyNames.COLLECTION_INDEX.equals( propertyName )
					|| CollectionPropertyNames.COLLECTION_MAX_INDEX.equals( propertyName )
					|| CollectionPropertyNames.COLLECTION_MIN_INDEX.equals( propertyName ) ) ) {
				throw new IllegalArgumentException( "Expecting index-related function call" );
			}
		}

		/**
		 * {@inheritDoc}
		 */
		public Type toType(String propertyName) throws QueryException {
			validate( propertyName );
			return queryableCollection.getIndexType();
		}

		/**
		 * {@inheritDoc}
		 */
		public String[] toColumns(String alias, String propertyName) throws QueryException {
			validate( propertyName );
			final String joinTableAlias = joinSequence.getFirstJoin().getAlias();
			if ( CollectionPropertyNames.COLLECTION_INDEX.equals( propertyName ) ) {
				return queryableCollection.toColumns( joinTableAlias, propertyName );
			}

			final String[] cols = queryableCollection.getIndexColumnNames( joinTableAlias );
			if ( CollectionPropertyNames.COLLECTION_MIN_INDEX.equals( propertyName ) ) {
				if ( cols.length != 1 ) {
					throw new QueryException( "composite collection index in minIndex()" );
				}
				return new String[] { "min(" + cols[0] + ')' };
			}
			else {
				if ( cols.length != 1 ) {
					throw new QueryException( "composite collection index in maxIndex()" );
				}
				return new String[] { "max(" + cols[0] + ')' };
			}
		}

		/**
		 * {@inheritDoc}
		 */
		public String[] toColumns(String propertyName) throws QueryException, UnsupportedOperationException {
			validate( propertyName );
			return queryableCollection.toColumns( propertyName );
		}
	}
}

Other Hibernate examples (source code examples)

Here is a short list of links related to this Hibernate FromElementType.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.