程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> JDK的Parser來解析Java源代碼詳解

JDK的Parser來解析Java源代碼詳解

編輯:關於JAVA

JDK的Parser來解析Java源代碼詳解。本站提示廣大學習愛好者:(JDK的Parser來解析Java源代碼詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是JDK的Parser來解析Java源代碼詳解正文


在JDK中,自帶了一套相干的編譯API,可以在Java中提議編譯流程,解析Java源文件然後獲得其語法樹,在JDK的tools.jar(OSX下可以在/Library/Java/JavaVirtualMachines/jdk_version/Contents/Home/lib中找到)中包括著這整套API,然則這卻不是Oracle和OpenJDK宣布中的地下API,是以關於這套API,並沒有官方的正式文檔來停止解釋。然則,也有很多項目應用了這套API來做了很多工作,例如年夜名鼎鼎的lombok應用了這套API在Annotation Processing階段修正了源代碼中的語法樹,終究成果相當於直接在源文件中拔出了新的代碼!

因為這套API今朝缺乏相干文檔,應用起來比擬艱苦,例如,解析源代碼中的一切變量,並打印出來:

public class JavaParser {
 
 private static final String path = "User.java";
 
 private JavacFileManager fileManager;
 private JavacTool javacTool;
 
 public JavaParser() {
  Context context = new Context();
  fileManager = new JavacFileManager(context, true, Charset.defaultCharset());
  javacTool = new JavacTool();
 }
 
 public void parseJavaFiles() {
  Iterable<!--? extends JavaFileObject--> files = fileManager.getJavaFileObjects(path);
  JavaCompiler.CompilationTask compilationTask = javacTool.getTask(null, fileManager, null, null, null, files);
  JavacTask javacTask = (JavacTask) compilationTask;
  try {
   Iterable<!--? extends CompilationUnitTree--> result = javacTask.parse();
   for (CompilationUnitTree tree : result) {
    tree.accept(new SourceVisitor(), null);
 
   }
  } catch (IOException e) {
   e.printStackTrace();
  }
 }
 
 static class SourceVisitor extends TreeScanner<void, void=""> {
 
  private String currentPackageName = null;
 
  @Override
  public Void visitCompilationUnit(CompilationUnitTree node, Void aVoid) {  
   return super.visitCompilationUnit(node, aVoid);
  }
 
  @Override
  public Void visitVariable(VariableTree node, Void aVoid) {
   formatPtrln("variable name: %s, type: %s, kind: %s, package: %s", 
     node.getName(), node.getType(), node.getKind(), currentPackageName);
   return null;
  }
 }
 
 public static void formatPtrln(String format, Object... args) {
  System.out.println(String.format(format, args));
 }
 
 public static void main(String[] args) {
 
  new JavaParser().parseJavaFiles();
 }
}</void,>

個中 User.java的代碼以下:

package com.ragnarok.javaparser;
 
import com.sun.istack.internal.Nullable;
import java.lang.Override;
 
public class User {
 
 @Nullable
 private String foo = "123123";
 private Foo a;
 
 public void UserMethod() {}
 
 static class Foo {
  private String fooString = "123123";
 
  public void FooMethod() {}
 }
}

履行下面的JavaParser成果以下:

variable: foo, annotaion: Nullable
variable name: foo, type: String, kind: VARIABLE, package: com.ragnarok.javaparser
variable name: a, type: Foo, kind: VARIABLE, package: com.ragnarok.javaparser

這裡我們是起首經由過程JavaCompiler.CompilationTask解析了源文件以後,再應用自界說的SourceVisitor(繼續自TreeScanner)來對源代碼的構造停止拜訪,在SourceVisitor類中,經由過程重載visitVariable來對一個編譯單位(單個源代碼文件)停止解析,拜訪個中的一切的變量,這裡可以看出,我們沒有方法拿到這個變量類型的全限制名(包括包名),只能拿到的對應的簡略名字,是以,類型切實其實定須要內部完成自行肯定,例如可以經由過程記載類地點的包名,遞歸的搜刮全部源代碼目次來跟蹤一切類的全限制名,查找import中能否包括對應的類型等。

TreeScanner中除visitVariable辦法外,還包括了年夜量其他的visitXYZ辦法,例如,可以遍歷一切的import,辦法界說,Annotation等,更詳細可以檢查OpenJDK中關於這個的源代碼

這裡再來看下別的一個例子,重載visitClass辦法,拜訪一切的外部類和類自己:

@Override
public Void visitClass(ClassTree node, Void aVoid) {
 formatPtrln("class name: %s", node.getSimpleName());
 for (Tree member : node.getMembers()) {
  if (member instanceof VariableTree) {
   VariableTree variable = (VariableTree) member;
   List<!--? extends AnnotationTree--> annotations = variable.getModifiers().getAnnotations();
   if (annotations.size() > 0) {
    formatPtrln("variable: %s, annotaion: %s", variable.getName(), annotations.get(0).getAnnotationType());
   } else {
    formatPtrln("variable: %s", variable.getName());
   }    
  }
 }
 return super.visitClass(node, aVoid);
 }

這裡簡略的打印了類名和變量的稱號,類型,annotation類型,履行下面的代碼,成果以下:

class name: User
variable: foo, annotaion: Nullable
variable: a
class name: Foo
variable: fooString



可以看出我們把類名和類中的變量都打印了出來。而在visitClass辦法中,我們可以經由過程getMembers辦法拿到類中一切的成員,包含變量,辦法,annotation等,分離對應著分歧的類型,例如變量就對應著VariableTree類型,辦法就對應的MethodTree類型。

總得來講,固然現實上應用其實不算特殊龐雜,然則因為缺乏文檔,對應用形成了很年夜的妨礙,並且今朝所引見的只是這套API的一少部門,後續我將會持續研討這套API的相干函數。

以上就是對JDK的Parser來解析Java源代碼 的材料整頓,後續持續彌補相干材料,感謝年夜家對本站的支撐!

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved