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

Hibernate example source code file (FromParser.java)

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

fromparser, hashmap, in, join_types, jointype, map, pathexpressionparser, queryable, queryable, queryexception, queryexception, querytranslatorimpl, string, string, util

The Hibernate FromParser.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.classic;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.QueryException;
import org.hibernate.hql.spi.QueryTranslator;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.sql.JoinType;

/**
 * Parses the from clause of a hibernate query, looking for tables and
 * aliases for the SQL query.
 */

public class FromParser implements Parser {

	private final PathExpressionParser peParser = new FromPathExpressionParser();
	private String entityName;
	private String alias;
	private boolean afterIn;
	private boolean afterAs;
	private boolean afterClass;
	private boolean expectingJoin;
	private boolean expectingIn;
	private boolean expectingAs;
	private boolean afterJoinType;
	private JoinType joinType = JoinType.INNER_JOIN;
	private boolean afterFetch;
	
	//support collection member declarations
	//e.g. "from Customer c, in(c.orders) as o"
	private boolean memberDeclarations;
	private boolean expectingPathExpression;
	private boolean afterMemberDeclarations;
	private String collectionName;

	private static final Map<String,JoinType> JOIN_TYPES = new HashMap();

	static {
		JOIN_TYPES.put( "left", JoinType.LEFT_OUTER_JOIN );
		JOIN_TYPES.put( "right", JoinType.RIGHT_OUTER_JOIN );
		JOIN_TYPES.put( "full", JoinType.FULL_JOIN );
		JOIN_TYPES.put( "inner", JoinType.INNER_JOIN );
	}

	public void token(String token, QueryTranslatorImpl q) throws QueryException {

		// start by looking for HQL keywords...
		String lcToken = token.toLowerCase();
		if ( lcToken.equals( "," ) ) {
			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: ," );
			expectingJoin = false;
			expectingAs = false;
		}
		else if ( lcToken.equals( "join" ) ) {
			if ( !afterJoinType ) {
				if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: join" );
				// inner joins can be abbreviated to 'join'
				joinType = JoinType.INNER_JOIN;
				expectingJoin = false;
				expectingAs = false;
			}
			else {
				afterJoinType = false;
			}
		}
		else if ( lcToken.equals( "fetch" ) ) {
			if ( q.isShallowQuery() ) throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
			if ( joinType == JoinType.NONE ) throw new QueryException( "unexpected token: fetch" );
			if ( joinType == JoinType.FULL_JOIN || joinType == JoinType.RIGHT_OUTER_JOIN ) {
				throw new QueryException( "fetch may only be used with inner join or left outer join" );
			}
			afterFetch = true;
		}
		else if ( lcToken.equals( "outer" ) ) {
			// 'outer' is optional and is ignored
			if ( !afterJoinType ||
					( joinType != JoinType.LEFT_OUTER_JOIN && joinType != JoinType.RIGHT_OUTER_JOIN )
			) {
				throw new QueryException( "unexpected token: outer" );
			}
		}
		else if ( JOIN_TYPES.containsKey( lcToken ) ) {
			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: " + token );
			joinType = JOIN_TYPES.get( lcToken );
			afterJoinType = true;
			expectingJoin = false;
			expectingAs = false;
		}
		else if ( lcToken.equals( "class" ) ) {
			if ( !afterIn ) throw new QueryException( "unexpected token: class" );
			if ( joinType != JoinType.NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
			afterClass = true;
		}
		else if ( lcToken.equals( "in" ) ) {
			if (alias == null ){
				memberDeclarations = true;
				afterMemberDeclarations = false;
			}
			else if ( !expectingIn ) {
				throw new QueryException( "unexpected token: in" );
			} else {
				afterIn = true;
				expectingIn = false;
			}
		}
		else if ( lcToken.equals( "as" ) ) {
			if ( !expectingAs ) throw new QueryException( "unexpected token: as" );
			afterAs = true;
			expectingAs = false;
		}
		else if ( "(".equals( token ) ){
			if( !memberDeclarations ) throw new QueryException( "unexpected token: (" );
			//TODO alias should be null here
			expectingPathExpression = true;
			
		}
		else if ( ")".equals( token ) ){
//			memberDeclarations = false;
//			expectingPathExpression = false;
			afterMemberDeclarations = true;
		}
		else {

			if ( afterJoinType ) throw new QueryException( "join expected: " + token );
			if ( expectingJoin ) throw new QueryException( "unexpected token: " + token );
			if ( expectingIn ) throw new QueryException( "in expected: " + token );

			// now anything that is not a HQL keyword

			if ( afterAs || expectingAs ) {

				// (AS is always optional, for consistency with SQL/OQL)

				// process the "new" HQL style where aliases are assigned
				// _after_ the class name or path expression ie. using
				// the AS construction

				if ( entityName != null ) {
					q.setAliasName( token, entityName );
				}
				else if ( collectionName != null ) {
					q.setAliasName( token, collectionName );
				}
				else {
					throw new QueryException( "unexpected: as " + token );
				}
				afterAs = false;
				expectingJoin = true;
				expectingAs = false;
				entityName = null;
				collectionName = null;
				memberDeclarations = false;
				expectingPathExpression = false;
				afterMemberDeclarations = false;

			}
			else if ( afterIn ) {

				// process the "old" HQL style where aliases appear _first_
				// ie. using the IN or IN CLASS constructions

				if ( alias == null ) throw new QueryException( "alias not specified for: " + token );

				if ( joinType != JoinType.NONE ) throw new QueryException( "outer or full join must be followed by path expression" );

				if ( afterClass ) {
					// treat it as a classname
					Queryable p = q.getEntityPersisterUsingImports( token );
					if ( p == null ) throw new QueryException( "persister not found: " + token );
					q.addFromClass( alias, p );
				}
				else {
					// treat it as a path expression
					peParser.setJoinType( JoinType.INNER_JOIN );
					peParser.setUseThetaStyleJoin( true );
					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
					if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
					String nm = peParser.addFromCollection( q );
					q.setAliasName( alias, nm );
				}

				alias = null;
				afterIn = false;
				afterClass = false;
				expectingJoin = true;
			}
			else if( memberDeclarations && expectingPathExpression ){
				expectingAs = true;
				peParser.setJoinType( JoinType.INNER_JOIN );
				peParser.setUseThetaStyleJoin( false );
				ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
				if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
				collectionName = peParser.addFromCollection( q );
				expectingPathExpression = false;
				memberDeclarations = false;
			}
			else {

				// handle a path expression or class name that
				// appears at the start, in the "new" HQL
				// style or an alias that appears at the start
				// in the "old" HQL style

				Queryable p = q.getEntityPersisterUsingImports( token );
				if ( p != null ) {
					// starts with the name of a mapped class (new style)
					if ( joinType != JoinType.NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
					entityName = q.createNameFor( p.getEntityName() );
					q.addFromClass( entityName, p );
					expectingAs = true;
				}
				else if ( token.indexOf( '.' ) < 0 ) {
					// starts with an alias (old style)
					// semi-bad thing about this: can't re-alias another alias.....
					alias = token;
					expectingIn = true;
				}
				else {

					// starts with a path expression (new style)

					// force HQL style: from Person p inner join p.cars c
					//if (joinType==NONE) throw new QueryException("path expression must be preceded by full, left, right or inner join");

					//allow ODMG OQL style: from Person p, p.cars c
					if ( joinType != JoinType.NONE ) {
						peParser.setJoinType( joinType );
					}
					else {
						peParser.setJoinType( JoinType.INNER_JOIN );
					}
					peParser.setUseThetaStyleJoin( q.isSubquery() );

					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
					entityName = peParser.addFromAssociation( q );

					joinType = JoinType.NONE;
					peParser.setJoinType( JoinType.INNER_JOIN );

					if ( afterFetch ) {
						peParser.fetch( q, entityName );
						afterFetch = false;
					}

					expectingAs = true;

				}
			}
		}

	}

	public void start(QueryTranslatorImpl q) {
		entityName = null;
		collectionName = null;
		alias = null;
		afterIn = false;
		afterAs = false;
		afterClass = false;
		expectingJoin = false;
		expectingIn = false;
		expectingAs = false;
		memberDeclarations = false;
		expectingPathExpression = false;
		afterMemberDeclarations = false;
		joinType = JoinType.NONE;
	}

	public void end(QueryTranslatorImpl q) {
		if( afterMemberDeclarations ){
			//The exception throwned by the AST query translator contains the error token location, respensent by line and colum, 
			//but it hard to get that info here.
			throw new QueryException("alias not specified for IN");
		}
	}

}

Other Hibernate examples (source code examples)

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