JDT中有兩套Java文件模型映射。
其核心類\接口分別為:
org.eclipse.jdt.core.IJavaElement和org.eclipse.jdt.core.dom.ASTNode
IJavaElement是Java Element的通用“協議”,即是對Java包、類、方法、變量、注解等等元素的規范。
它可以用於映射java文件,也可以映射class文件,任何java方面的元素都能找到其對應的實現類。
ASTNode是Java ast(語法分析樹)的建模,用於構建java語句,它只能用於java文件分析,對class文件無能為力。其側重點是語法。
舉個例子,一個類,比如java.util.List
在IJavaElement中要使用,必須有java.util.List作為IType存在。
在ASTNode中使用,則只需要用戶知道“java.util.List"這個字符串即可。
IJavaElement常用於分析Java相關的元素
ASTNode常用來解析和構建Java文件
在實際使用中,我們經常會涉及到兩個實現類之間的轉化。
比如根據IMethod來查找MethodDeclaration
JDT提供了一個方法的工具類NodeFinder。使用方式如下:
NodeFinder.perform(domUnit,
method.getSourceRange())
這里要特別注意的是sourceRange,它代表了指定對象(類、方法等)在java類定義里的儲存位置,它有兩個標量,offset和length。
所以,我們還可以使用以下方式:
NodeFinder.perform(domUnit,mj.getOffset(),ms.getLength());
這里要特別注意的地方是,如果該method的源碼具備注釋(comment),該方法會產生問題,會找不到MethodDeclaration,取而代之的是父級的TypeDeclaration。
原因在於jdt(至少是3.7.0及更早版本)的BUG,IMethod記錄comment的offset和length,但是ASTNode並沒有相應的記錄,如果使用上方的方法,NodeFinder會認為范圍超限,屬於類范圍而非方法范圍。
所以,我們需要一個小小的改動:
IMethod method = (IMethod) methodElement
.getAncestor(IJavaElement.METHOD);
try {
ISourceRange ms = method.getSourceRange();
ISourceRange mj = method.getJavadocRange();
if (ms.getOffset() == mj.getOffset()) {
// 消除注釋的影響
return (MethodDeclaration) NodeFinder.perform(domUnit,
method.getSourceRange());
} else {
return (MethodDeclaration) NodeFinder.perform(domUnit,
mj.getOffset(),
ms.getLength() - mj.getOffset() + ms.getOffset());
}
} catch (JavaModelException e) {
e.printStackTrace();
}
注意紅色部分,它用於去除多余的注釋部分,計算出准確的方法體范圍。