views:

840

answers:

2

Can anyone point me out, how can I parse/evaluate HQL and get map where key is table alias and value - full qualified class name.

E.g. for HQL

SELECT a.id from Foo a INNER JOIN a.test b

I wish to have pairs:

a, package1.Foo

b. package2.TestClassName

It's relatively easy to do for result set

HQLQueryPlan hqlPlan = ((SessionFactoryImpl)sf).getQueryPlanCache().getHQLQueryPlan( getQueryString(), false, ((SessionImpl)session).getEnabledFilters() );
String[] aliases = hqlPlan.getReturnMetadata().getReturnAliases();
Type[] types = hqlPlan.getReturnMetadata().getReturnTypes();

See details here.

+1  A: 

Hardly a good way of doing it, but it seems you can get the AST through some internal interfaces and traverse this:

QueryTranslator[] translators = hqlPlan.getTranslators();
AST ast = (AST)((QueryTranslatorImpl)translators[0]).getSqlAST();
    new NodeTraverser(new NodeTraverser.VisitationStrategy() {
    public void visit(AST node) {
        if(node.getType() == SqlTokenTypes.FROM_FRAGMENT || node.getType() = SqlTokenTypes.JOIN_FRAGMENT) {
            FromElement id = (FromElement)node;
            System.out.println(node+": "+id.getClassAlias()+" - "+id.getClassName());
        }
    }
}).traverseDepthFirst(ast);

So this seems to retrieve the alias-mappings from the compiled query, but I would be very careful using this solution: it typecasts objects to subclasses not usually visible to a hibernate-client and interprets the AST based on guessing the semantics of the different nodes. This might not work on all HQL-statements, and might not work, or have different behaviour, on a future hibernate-version.

Rolf Rander
I generate dynamically HQL based on our internal API (criteria panes etc.) and for filtering conditions (i.e. WHERE part) need to know alias for each class in the HQL.
FoxyBOA
Looks like SqlTokenTypes.ALIAS_REF is not what I'm looking for. In my example above result will be "a, package1.Foo", but I need "b, package2.TestClassName" as well. I mean ALIAS_REF process "SELECT" part instead of "FROM".
FoxyBOA
Regarding your question of using Criteria API.I have two reasons:1. Legacy code2. HQL allows you construct so called report queries (extract exactly data which you need and don't construct whole object). See link for details http://rongou.blogspot.com/2005/08/hibernate-report-query.html
FoxyBOA
Oh, I didn't know report quries, this was very interresting. The whole point of Hibernate is ofcourse to map data from tables to objects, but for some applications tables are a better fit, and report-queries seems to fit exactly this.
Rolf Rander
Your are right. And I need that reverse engineering of HQL for controller of our reporting module.
FoxyBOA
A: 

I found right solution for my question. Your original post was almost correct except that part:

if(node.getType() == SqlTokenTypes.FROM_FRAGMENT || node.getType() == SqlTokenTypes.JOIN_FRAGMENT) {
 FromElement id = (FromElement)node;
 System.out.println(node+": "+id.getClassAlias()+" - "+id.getClassName());
}

Please correct your answer answer and I accept it.

FoxyBOA