利用JDT 来分析java 源代码

本文介绍了一种使用Eclipse JDT库遍历Java源代码以查找并提取所有包含SELECT关键字的SQL语句的方法。该方法通过分析项目源代码帮助开发者及早发现可能存在的查询性能问题。

项目里需要扫代码的sql,主要是想找出所有用到的sql。 将相关的sql 提交给DBA 来分析,希望在最早的时间发现潜在的查询性能问题。

想想eclipse 里面用到的JDT 能分析java 源代码, 如果我们能分析项目里的源代码利用ASTParser 就可以找到相关的SQL 定义了。

 

其实已经有人想到这个 http://www.programcreek.com/2011/01/a-complete-standalone-example-of-astparser

,已经自己整理过所有会依赖的jar,机器重装本地的 repository给丢了。  所有就直接用这个链接里面给的一个zip 包, 但是在我现在用到的eclipse 还需要 一个 org.eclipse.text_3.5.0.jar 。

 

为了这个代码不要弄丢了,直接放一份 当然没有项目里面的信息

package com.bwang.jdt;


import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.List;

import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AbstractTypeDeclaration;
import org.eclipse.jdt.core.dom.BodyDeclaration;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.FieldDeclaration;

public class SqlExtractor {
	private BufferedWriter writer;
	private long counter = 0;
	private final String fileRoot;
	private final String logFileName;

	public static void main (String[] args) {
		if (args.length < 2) {
			System.out.println("Please provide the parameters:");
			System.out.println("SqlExtractor  codeOfRoot logFileName");
			System.exit(-1);
		}
		SqlExtractor sqlExtractor = new SqlExtractor(args);
		sqlExtractor.extractSql();
	}

	SqlExtractor(String[] args) {
		fileRoot = args[0];
		logFileName =  args[1];

		try {
			writer = new BufferedWriter(new FileWriter(new File(logFileName)));
		} catch(IOException e) {

		}
	}

	private void analyzeOneFile(String sourceFile,  Writer writer) {
		String source = getFileContent(sourceFile);
		ASTParser parser = ASTParser.newParser(AST.JLS3);
		parser.setSource(source.toCharArray());
		CompilationUnit unit = (CompilationUnit)parser.createAST(null);
		unit.recordModifications();
		StringBuilder sb = new StringBuilder();
		List<AbstractTypeDeclaration> types = unit.types();
		for (AbstractTypeDeclaration type : types) {
			if (type.getNodeType() == ASTNode.TYPE_DECLARATION) {
				// Class def found
				List<BodyDeclaration> bodies = type.bodyDeclarations();
				for (BodyDeclaration body : bodies) {
					if (body.getNodeType() == ASTNode.FIELD_DECLARATION /*&& 
	                		((FieldDeclaration)body).getType().equals(Type.S) */	) {
						FieldDeclaration field = (FieldDeclaration)body;
						if(field.toString().toLowerCase().indexOf("select") >=0) {
							sb.append(field.toString());
							counter++;
						}
					}
				}
			}
		}
		if (sb.length() > 0) {

			try {
				if (counter > 0) {
					writer.append("\n\n");
				}
				sourceFile = sourceFile.replace(fileRoot, "");
				sourceFile = sourceFile.replace("\\", "/");
				writer.append(sourceFile + "\n");
				String content = sb.toString();
				content = content.replace("\" +", "\"\n\t\t+ ");
				content = content.replace("\"+", "\"\n\t\t+ ");
				writer.append(content);
			}catch(IOException ioe) {

			}
		}

	}

	private void extractSql() {
		File folder = new File(fileRoot);
		List<File> poms = new ArrayList<File>();
		handleOneFolder(folder, poms);

		System.out.println("begin to analyze files of :" + poms.size());
		try {
			int index = 1;
			for(File f : poms) {

				System.out.println("begin to analyze file : " + index + " " + f.getName());
				analyzeOneFile(f.getPath(), writer);
				index++;
			}
		}
		finally {
			try {
				writer.flush();
				writer.close();
			} catch(IOException e) {

			}
		}
		System.out.println("successfully find sql count:" + counter);
	}

	private void handleOneFolder(File folder,  List<File>  poms) {
		if(!folder.isDirectory()) {
			return;
		}

		String[] files = folder.list();
		for(String oneFile : files) {
			String fullFileName = folder.getPath() + "/" + oneFile;
			if (fullFileName.endsWith(".java") && fullFileName.indexOf("src\\test\\java\\") < 0) {
				poms.add(new File(fullFileName));
				continue;
			} 
			File f = new File(fullFileName);
			if (f.isDirectory()) {
				handleOneFolder(f, poms);
			}
		}
	}

	private String getFileContent(String fName) {
		try {	
			File file = new File(fName);
			BufferedReader in = new BufferedReader(new FileReader(file));
			StringBuffer buffer = new StringBuffer(); 
			String line = null;
			while (null != (line = in.readLine())) {
				buffer.append("\t" + line);
				buffer.append("\n");
			}	

			return buffer.toString();

		}
		catch (IOException e) {
			throw new RuntimeException(e);
		}
	}
}

 

思路也简单就是遍历 codeOfRoot 下面的所有java 文件, 找到 所有的field 定义的值里面包含 select 关键字的 field,  然后将所有这些满足条件的都写到一个log 文件。 

 

到时候将log 文件发给DBA 就行了。 当然还可以更进一步来个CI,  可以定期去扫项目的代码, 然后比较产生的log 文件的变化。 然后DBA 定期看 变化的SQL 就好了, 是不是很酷。

 

 

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值