`
ayufox
  • 浏览: 276247 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

AST构建Hibernat动态查询

阅读更多
一、效果
java 代码
 
  1. public class HqlCompilerImplTest extends TestCase  
  2. {  
  3.     private IHqlCompiler compiler = new HqlCompilerImpl();  
  4.   
  5.     public void test1()  
  6.     {  
  7.         Hql hql = compiler.compile("from User u where u.username = :username and u.age = :age order by u.username,u.age",  
  8.                 new MapContext());  
  9.         assertEquals("from User u order by u.username,u.age", hql.getHql());  
  10.         assertEquals(0, hql.getParameters().length);  
  11.     }  
  12.   
  13.     public void test2)  
  14.     {  
  15.         MapContext context = new MapContext();  
  16.         context.add("username""ray");  
  17.           
  18.         Hql hql = compiler  
  19.                 .compile(  
  20.                         "from User u where u.username = :username and u.age = :age order by u.username,u.age",  
  21.                         context);  
  22.           
  23.         assertEquals(  
  24.                 "from User u where u.username = :username order by u.username,u.age",  
  25.                 hql.getHql());  
  26.         assertEquals(1, hql.getParameters().length);  
  27.         assertEquals("username", hql.getParameters()[0].getName());  
  28.         assertEquals("ray", hql.getParameters()[0].getValue());  
  29.     }  
  30.   
  31.     public void test3()  
  32.     {  
  33.         MapContext context = new MapContext();  
  34.         context.add("username""ray");  
  35.         context.add("age"new Integer(10));  
  36.           
  37.         Hql hql = compiler  
  38.         .compile(  
  39.                 "from User u where u.username = :username and u.age = :age order by u.username,u.age",  
  40.                 context);  
  41.         assertEquals(  
  42.                 "from User u where (u.username = :username and u.age = :age) order by u.username,u.age",  
  43.                 hql.getHql());  
  44.         assertEquals(2, hql.getParameters().length);  
  45.         assertEquals("username", hql.getParameters()[0].getName());  
  46.         assertEquals("ray", hql.getParameters()[0].getValue());  
  47.         assertEquals("age", hql.getParameters()[1].getName());  
  48.         assertEquals(new Integer(10), hql.getParameters()[1].getValue());  
  49.     }  
  50. }  

二、基本接口
java 代码
 
  1. package com.ayufox.framework.core;  
  2.   
  3. /** 
  4.  * @author ray 
  5.  * 
  6.  */  
  7. public interface Context  
  8. {  
  9.     Object get(String name);  
  10. }  
java 代码
 
  1. package com.ayufox.framework.core.dao.hqlx;  
  2.   
  3. import com.ayufox.framework.core.Context;  
  4. import com.ayufox.framework.core.dao.hql.Hql;  
  5.   
  6. /** 
  7.  * @author ray 
  8.  * 
  9.  */  
  10. public interface IHqlCompiler  
  11. {  
  12.     Hql compile(String hql, Object ... values);  
  13.       
  14.     Hql compile(String hql, Context context);  
  15. }  
三、实现
java 代码
 
  1. package com.ayufox.framework.core.dao.hqlx.ast;  
  2.   
  3. import java.io.ByteArrayOutputStream;  
  4. import java.io.PrintStream;  
  5. import java.util.Collections;  
  6. import java.util.HashMap;  
  7.   
  8. import org.apache.commons.logging.Log;  
  9. import org.apache.commons.logging.LogFactory;  
  10. import org.hibernate.hql.ast.HqlParser;  
  11.   
  12. import antlr.RecognitionException;  
  13. import antlr.TokenStreamException;  
  14. import antlr.collections.AST;  
  15.   
  16. import com.ayufox.framework.core.Context;  
  17. import com.ayufox.framework.core.cache.Cache;  
  18. import com.ayufox.framework.core.cache.MapCache;  
  19. import com.ayufox.framework.core.dao.hql.Hql;  
  20. import com.ayufox.framework.core.dao.hqlx.DynamicMapContext;  
  21. import com.ayufox.framework.core.dao.hqlx.IHqlCompiler;  
  22. import com.ayufox.framework.core.dao.hqlx.IllegalSyntaxException;  
  23.   
  24. /** 
  25.  * @author ray 
  26.  * 
  27.  */  
  28. public class HqlCompilerImpl implements IHqlCompiler  
  29. {  
  30.     private final static Log LOG = LogFactory.getLog(HqlCompilerImpl.class);  
  31.   
  32.     private Cache astCache = new MapCache(Collections  
  33.             .synchronizedMap(new HashMap()));  
  34.   
  35.     public void setAstCache(Cache astCache)  
  36.     {  
  37.         this.astCache = astCache;  
  38.     }  
  39.   
  40.     /* (non-Javadoc) 
  41.      * @see com.konceptusa.framework.core.dao.hqlx.IHqlCompiler#compile(java.lang.String, java.lang.Object[]) 
  42.      */  
  43.     public Hql compile(String hql, Object... values)  
  44.     {  
  45.         return compile(hql, new DynamicMapContext(values));  
  46.     }  
  47.   
  48.     /* (non-Javadoc) 
  49.      * @see com.konceptusa.framework.core.dao.hqlx.IHqlCompiler#compile(java.lang.String, com.konceptusa.framework.core.Context) 
  50.      */  
  51.     public Hql compile(String hql, Context context)  
  52.     {  
  53.         if (hql == null || context == null)  
  54.         {  
  55.             throw new IllegalArgumentException("hql or context can't be null");  
  56.         }  
  57.   
  58.         AST ast = getRootAST(hql);  
  59.   
  60.         HqlCompileExecutor compilerContext = new HqlCompileExecutor(ast,  
  61.                 context);  
  62.         return compilerContext.build();  
  63.     }  
  64.   
  65.     protected AST getRootAST(String hql)  
  66.     {  
  67.         AST ast = (AST) this.astCache.get(hql);  
  68.         if (ast == null)  
  69.         {  
  70.             ast = createAST(hql);  
  71.             this.astCache.put(hql, ast);  
  72.             if (LOG.isDebugEnabled())  
  73.             {  
  74.                 LOG.debug("get ast[" + ast + "] from cache for hql[" + hql  
  75.                         + "]");  
  76.             }  
  77.         }  
  78.         return ast;  
  79.     }  
  80.   
  81.     private AST createAST(String hql)  
  82.     {  
  83.         HqlParser parser = HqlParser.getInstance(hql);  
  84.         try  
  85.         {  
  86.             parser.statement();  
  87.         }  
  88.         catch (RecognitionException e)  
  89.         {  
  90.             throw new IllegalSyntaxException(e);  
  91.         }  
  92.         catch (TokenStreamException e)  
  93.         {  
  94.             throw new IllegalSyntaxException(e);  
  95.         }  
  96.         AST ast = parser.getAST();  
  97.         parser.getParseErrorHandler().throwQueryException();  
  98.         if (LOG.isDebugEnabled())  
  99.         {  
  100.             ByteArrayOutputStream baos = new ByteArrayOutputStream();  
  101.             parser.showAst(ast, new PrintStream(baos));  
  102.             LOG.debug("AST:" + new String(baos.toByteArray()));  
  103.         }  
  104.         return ast;  
  105.     }  
  106. }  

分享到:
评论
3 楼 onlyerlee 2007-09-27  
能把源码发到我邮箱里来吗?我想运行下知道是怎样的效果. onlyerli@ecvision.com
2 楼 pigfly 2007-05-27  
这样还是要自己写hql语句,可不可以根据结果集合自动拼凑hql呢
1 楼 ayufox 2007-05-25  
package com.ayufox.framework.core.dao.hqlx.ast;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.hql.antlr.SqlTokenTypes;

import antlr.collections.AST;

import com.ayufox.framework.core.Context;
import com.ayufox.framework.core.common.CommonUtils;
import com.ayufox.framework.core.dao.hql.Hql;
import com.ayufox.framework.core.dao.hql.Parameter;

/**
 * @author ray
 *
 */
public class HqlCompileExecutor implements SqlTokenTypes
{
	private final static Log LOG = LogFactory.getLog(HqlCompileExecutor.class);
	private final static Map NODE_TYPE_MAP = new HashMap();
	static
	{
		Field[] fields = SqlTokenTypes.class.getFields();
		for (int i = 0; i < fields.length; i++)
		{
			Field field = fields[i];
			int modifiers = field.getModifiers();
			if (Modifier.isPublic(modifiers) && Modifier.isStatic(modifiers)
					&& Modifier.isFinal(modifiers))
			{
				String name = field.getName();
				try
				{
					Object value = field.get(null);
					NODE_TYPE_MAP.put(value, name);
				}
				catch (IllegalAccessException ex)
				{
					LOG.error("Imposible", ex);
				}
			}
		}
	}

	protected Hql hql;
	protected List<Parameter> parameters;
	protected Context context;

	private AST root;

	public HqlCompileExecutor(AST root, Context context)
	{
		init(root, context);
	}
	
	protected HqlCompileExecutor()
	{
		
	}
	
	protected void init(AST root, Context context)
	{
		this.context = context;
		this.root = root;
		this.parameters = new ArrayList<Parameter>();
	}

	public Hql build()
	{
		if (this.hql == null)
		{
			String hql = buildHql();
			if (LOG.isDebugEnabled())
			{
				LOG.debug("hql:" + hql);
				for (int i = 0; i < this.parameters.size(); i++)
				{
					LOG.debug("  parameter[" + i + "]:name=["
							+ this.parameters.get(i).getName() + "],value=["
							+ this.parameters.get(i).getValue() + "]");
				}
			}
			this.hql = new Hql(hql, this.parameters
					.toArray(new Parameter[this.parameters.size()]));
		}
		return this.hql;
	}

	protected String buildHql()
	{
		StringBuffer buffer = new StringBuffer();
		print(buffer, this.root);
		return buffer.toString();
	}

	protected void print(StringBuffer buffer, AST ast)
	{
		switch (ast.getType())
		{
			case QUERY: //查询根节点
				printChildren(buffer, ast, " ");
				break;
			case RANGE: //FROM根节点
				printRANGE(buffer, ast);
				break;
			case IDENT:
			case ALIAS:
			case ROW_STAR: //*
			case DISTINCT:
			case ALL:
			case NUM_INT:
			case NUM_DOUBLE:
			case NUM_FLOAT:
			case NUM_LONG:
				printText(buffer, ast);
				break;
			case INNER:
			case OUTER:
			case FULL:
			case LEFT:
			case RIGHT:
				printText(buffer, ast);
				buffer.append(" join");
				break;
			case JOIN:
				printJOIN(buffer, ast);
				break;
			case FROM:
				printSelfAndChildren(buffer, ast, " ");
				break;
			case SELECT:
				printSelfAndChildren(buffer, ast, ",");
				break;
			case SELECT_FROM:
				printSELECT_FROM(buffer, ast);
				break;
			case COUNT:
			case AGGREGATE: //聚合函数
				printFunction(buffer, ast);
				break;
			case DOT: //.
				printDOT(buffer, ast);
				break;
			case AND:
			case OR:
				printLinkWord(buffer, ast);
				break;
			case WHERE:
				printWhere(buffer, ast);
				break;
			case CONSTRUCTOR:
				printCONSTRUCTOR(buffer, ast);
				break;
			case LIKE:
			case NOT_LIKE:
			case EQ:
			case GT:
			case GE:
			case LT:
			case LE:
			case IN:
			case NOT_IN:
				printCondition(buffer, ast);
				break;
			case BETWEEN:
			case NOT_BETWEEN:
				printBETWEEN(buffer, ast);
				break;
			case IN_LIST: //in
				printInList(buffer, ast);
				break;
			case COLON: //:
				printCOLON(buffer, ast);
				break;
			case ORDER:
				printORDER(buffer, ast);
				break;
			case GROUP:
				buffer.append("group by ");
				printChildren(buffer, ast, ",");
				break;
			case ASCENDING:
			case DESCENDING:
				printText(buffer, ast);
			    break;
			default:
				LOG.warn("Incognizance node, type["
						+ NODE_TYPE_MAP.get(ast.getType()) + "("
						+ ast.getType() + ")] text[" + ast.getText() + "]");
		}
	}

	protected void printCONSTRUCTOR(StringBuffer buffer, AST ast)
	{
		buffer.append("new ");
		AST constructor = ast.getFirstChild();
		print(buffer, constructor);
		buffer.append('(');
		AST next = constructor.getNextSibling();
		while (next != null)
		{
			if (buffer.charAt(buffer.length()-1) != '(')
			{
				buffer.append(',');
			}
			print(buffer, next);
			next = next.getNextSibling();
		}
		buffer.append(')');
	}

	protected void printORDER(StringBuffer buffer, AST ast)
	{
		buffer.append("order by ");
		AST child = ast.getFirstChild();
		AST next = null;
		while (child != null)
		{
			print(buffer, child);
			next = child.getNextSibling();
			if (next != null)
			{
				if (next.getType() == DESCENDING || next.getType() == ASCENDING)
				{
					buffer.append(" ");
				}
				else
				{
					buffer.append(",");
				}
			}
			child = next;
		}
	}

	protected void printRANGE(StringBuffer buffer, AST ast)
	{
		printChildren(buffer, ast, " ");

		AST next = ast.getNextSibling();
		if (next != null && next.getType() == RANGE)
		{
			buffer.append(",");
		}
	}

	protected void printInList(StringBuffer buffer, AST ast)
	{
		buffer.append("(");
		printChildren(buffer, ast, "");
		buffer.append(")");
	}

	protected void printWhere(StringBuffer buffer, AST ast)
	{
		//where节点下只有一个子节点
		int length = buffer.length();
		AST child = ast.getFirstChild();

		print(buffer, child);

		if (buffer.length() > length)
		{
			buffer.insert(length, ast.getText() + " ");
		}
	}

	/*
	 * 连接词,即and和or
	 */
	protected void printLinkWord(StringBuffer buffer, AST ast)
	{
		int sourceLength = buffer.length();
		AST left = ast.getFirstChild();
		AST right = left.getNextSibling();

		print(buffer, left);

		int middleLength = buffer.length();

		print(buffer, right);

		int allLength = buffer.length();

		//or/and的左表达式和右表达式都存在,需要加上括号和连接词
		if ((allLength > middleLength) && (middleLength > sourceLength))
		{
			buffer.insert(sourceLength, "(");

			buffer.insert(middleLength + 1, " " + ast.getText() + " ");

			buffer.append(")");
		}
	}

	/*
	 * :
	 */
	protected void printCOLON(StringBuffer buffer, AST ast)
	{
		int length = buffer.length();
		printChildren(buffer, ast, "");
		String name = buffer.substring(length, buffer.length()).replace('_',
				'.');
		Object value = context.get(name);
		if (CommonUtils.isEmpty(value))
		{
			throw new ValueNotExistException(name);
		}
		buffer.insert(length, ast.getText());
		this.parameters.add(new Parameter(name, value));
	}

	protected void printText(StringBuffer buffer, AST ast)
	{
		buffer.append(ast.getText());
	}

	/*
	 * 函数,如avg(..)、count(...)等
	 */
	protected void printFunction(StringBuffer buffer, AST ast)
	{
		buffer.append(ast.getText());
		buffer.append("(");
		printChildren(buffer, ast, " ");
		buffer.append(")");
	}

	/*
	 * .
	 */
	protected void printDOT(StringBuffer buffer, AST ast)
	{
		AST left = ast.getFirstChild();
		print(buffer, left);

		buffer.append(ast.getText());

		AST right = left.getNextSibling();
		print(buffer, right);
	}

	/*
	 * 打印所有子节点
	 * @param buffer 结果输出为止
	 * @param ast AST树
	 * @param join 子节点间连接符
	 */
	protected void printChildren(StringBuffer buffer, AST ast, String join)
	{
		AST child = ast.getFirstChild();
		while (child != null)
		{
			print(buffer, child);
			child = child.getNextSibling();
			if (child != null)
			{
				buffer.append(join);
			}
		}
	}

	/*
	 * 打印自身,然后再打印子节点
	 * @param buffer 
	 * @param ast
	 * @param join
	 * @param selfJoin
	 */
	protected void printSelfAndChildren(StringBuffer buffer, AST ast,
			String join)
	{
		buffer.append(ast.getText());
		buffer.append(" ");
		printChildren(buffer, ast, join);
	}

	/*
	 * join
	 */
	protected void printJOIN(StringBuffer buffer, AST ast)
	{
		int length = buffer.length();
		printChildren(buffer, ast, " ");
		if (!buffer.substring(length, buffer.length()).contains(ast.getText()))
		{
			buffer.insert(length, "join ");
		}
	}

	protected void printSELECT_FROM(StringBuffer buffer, AST ast)
	{
		AST from = ast.getFirstChild();
		AST select = from.getNextSibling();
		if (select != null)
		{
			print(buffer, select);
			buffer.append(" ");
		}
		print(buffer, from);
	}

	protected void printBETWEEN(StringBuffer buffer, AST ast)
	{
		int length = buffer.length();
		AST property = ast.getFirstChild();
		AST first = property.getNextSibling();
		AST second = first.getNextSibling();
		try
		{
			print(buffer, property);
			buffer.append(" ");
			printText(buffer, ast);
			buffer.append(" ");
			print(buffer, first);
			buffer.append(" and ");
			print(buffer, second);
		}
		catch (ValueNotExistException e)
		{
			if (buffer.lastIndexOf(":") > length)
			{
				this.parameters.remove(this.parameters.size() - 1);
			}
			//将已输出的部分截断
			buffer.setLength(length);
		}
	}

	/*
	 * 双操作数条件式,譬如like、=、in等等
	 */
	protected void printCondition(StringBuffer buffer, AST ast)
	{
		int length = buffer.length();
		AST left = ast.getFirstChild();
		print(buffer, left);

		buffer.append(" ");
		buffer.append(ast.getText());
		buffer.append(" ");

		AST right = left.getNextSibling();

		try
		{
			print(buffer, right);
		}
		catch (ValueNotExistException e)
		{
			//将已输出的部分截断
			buffer.setLength(length);
		}
	}
}

相关推荐

    三种查询方式跟踪Hibernate源码

    在执行`createCriteria()`或`createCriteriaJoin()`等方法时,Hibernate会构建一个表示查询条件的抽象语法树(AST)。`org.hibernate.criterion`包中的类如`DetachedCriteria`、`Expression`等用于构建这些条件。...

    Hibernate的查询 测试的架子

    QBC则通过构建Criteria对象来执行查询,这种方式更为灵活,可以动态构建查询条件。Criteria API是JPA2.0引入的新特性,相比HQL和QBC,它更加强大且类型安全。 接下来,我们聚焦于`测试架子`。在软件开发中,测试是...

    hibernate3.2官方源代码

    另外,Criteria API提供了一种更加灵活的查询方式,允许在运行时动态构造查询条件。 6. **事件与拦截器:** - Hibernate的`org.hibernate.event`和`org.hibernate.interceptor`包支持事件监听和拦截器机制,允许...

    java模仿hibernate

    3. **Criteria查询**:Hibernate提供了一种灵活的查询方式,不依赖于SQL,而是通过Criteria对象构建查询。我们可以创建一个类似的查询API,允许用户基于对象属性进行查询。 4. **HQL(Hibernate Query Language)**...

    AST.getLine()I 解决方案

    在Java编程中,`antlr.collections.AST.getLine()`方法是用来获取ANTLR解析树中某个节点的行号,这在处理语法分析和编译时非常有用。然而,当你遇到`java.lang.NoSuchMethodError: antlr.collections.AST.getLine()I...

    Hibernate官方网站源代码调试

    重点分析`org.hibernate.hql.ast.ASTQueryTranslatorFactory`和`org.hibernate.criterion.Criterion`接口。 3. **实体管理与状态转换**:实体管理是Hibernate的核心功能之一,包括持久化、加载、更新和删除等操作。...

    Windows 下整合 weblogic10 jsf1.2 hibernate3

    - **JSF 1.2**:JSF 1.2 是 JSF 的早期版本,支持基本的 MVC 架构模式,用于构建动态网页应用程序。 - **Hibernate 3**:Hibernate 3 是一个对象关系映射框架,简化了数据库操作,支持懒加载等高级特性。 - **...

    基于java的SQL解析类库 SQLJEP.zip

    通过SQLJEP,开发者可以轻松地获取到SQL语句的各个部分,如表名、列名、条件、联接等,这对于构建动态查询或实现复杂的数据过滤逻辑非常有用。 使用SQLJEP库,你可以: 1. **SQL语句解析**:将用户输入的SQL字符串...

    Linux 下整合 weblogic12c jsf1.2 Hibernate3

    具体来说,当使用 Hibernate 3 时,可能会遇到与 `org.hibernate.hql.ast.HqlToken` 相关的异常。这是因为 WebLogic 12c 使用了与 Hibernate 3 不兼容的 ANTLR 版本。 解决方法如下: 1. **替换 ANTLR 版本**: -...

    hibernater3.x部分类

    《Hibernate 3.x 部分类...总的来说,虽然Hibernate 3.x的某些包中可能缺失ANTLR相关的类文件,但通过理解和重构这些关键组件,我们可以深入掌握Hibernate的工作原理,并能更好地利用它来构建高效、稳定的数据库应用。

    jmesa 入门

    同时,它的动态性比Hibernate等ORM框架更强,更适用于复杂的查询需求。 ### 7. 应用场景 JMESa适用于那些需要灵活、动态SQL查询的场景,比如数据清洗、报表生成、复杂数据分析等。 ### 8. 进阶使用 除了基本的...

    MyEclipse报错说明

    应修改Spring配置文件中的`hibernate.query.factory_class`属性,确保指向正确的HQL翻译器工厂,如`org.hibernate.hql.ast.ASTQueryTranslatorFactory`。 5. **quartz Caused by: java.lang.NoSuchMethodError: org...

    Java常见异常

    2. **ClassNotFoundException: org.hibernate.hql.ast.HqlToken** 这意味着Java无法找到指定的类,可能是因为Hibernate库未正确导入或版本不匹配。确认项目构建路径中包含了正确的Hibernate库,并且版本与代码兼容...

    SQL Parser

    语法分析则根据这些标记构建AST,确保SQL语句符合特定的语法规则。 3. **抽象语法树(AST)** AST是编程语言中的一个重要概念,它以树状形式展示了程序的结构。在SQLParser中,每个节点代表SQL语句的一部分,如...

    velocity2

    在 Velocity2 中,可以通过模板轻松地展示由 Hibernate 查询获取的数据。 - **Struts**:是基于 MVC(Model-View-Controller)设计模式的 Web 应用框架。Velocity2 可以作为 Struts 的视图层,负责生成动态 HTML ...

    JPA 开发中遇到的错误

    org.hibernate.hql.ast.QuerySyntaxException: person is not mapped 此异常表明在HQL查询语句中引用了一个未被持久化类映射的对象或属性。例如,当你尝试查询一个名为`Person`的实体时,如果`Person`实体并未正确...

    laba-8-Ast-And-Shin:8个laba Astapkovich和shinoda

    如果“laba-8-Ast-And-Shin”是一个Java项目,那么可能涉及到使用Java进行编码、项目构建、版本控制、测试、部署等方面的知识。由于没有具体代码或文档,我们只能根据这些基本信息推测项目的性质。如果你能提供更多...

    groovy初学者的福音

    7. **AST转换**:在编译期间,Groovy允许开发者应用AST(抽象语法树)转换,这可以用来插入自定义的代码优化或者行为。 8. ** Grape**:Grape是Groovy的依赖管理系统,可以自动下载和管理项目所需的库。 9. **...

Global site tag (gtag.js) - Google Analytics