最近公司要求我做一個可以生成代碼的工具,需求爲像SWT-Desinger那樣,多頁編輯器,一頁顯示源代碼,另外一頁用表格的形式顯示類的屬性,要求可以修改,這也不是什麼和困難的事情,不過以前沒做過這樣的東西,還得找找資料來研究研究,發現有個叫AST的東西,是Eclipse提供的工具,以前聽說過,不過不怎麼用,經過一段時間的學習,發現這東西還真不賴,功能挺強大的,像Eclipse的重構功能就是通過這個AST來實現的,AST全名叫抽象語法樹,不過功能強是強大,用起來有點麻煩,很容易出錯。
今天在用這個AST生成一個Java文件,我是先通過SWT-Designer生成了一個JFace的ApplicationWindow的文件,上面就簡單的放一個按鈕,單擊後彈出一個對話框,然後顯示信息,功能是很簡單,經過一天的不斷嘗試,終於通過了編譯,直接運行出來了,可以看到我的對話框了,那下面來介紹一下怎麼使用這個東西
parser.setSource("".toCharArray());
CompilationUnit unit = (CompilationUnit) parser.createAST(null);
unit.recordModifications();
AST ast = unit.getAST();
上面的代碼是生成一個空的編譯單元,也就是我們的,java 文件了,我們通過ASTParser.newParser(AST.JLS3);來指定遵守的Java規範,如果是JLS2的話是指定Java 1.4的編譯規範,那麼 JLS3 爲遵守Java 5 以上的規範
unit.setPackage(packageDeclaration);
packageDeclaration.setName(ast.newSimpleName("astdemo"));
上面是生成Java文件的包, 結果爲 package astdemo;
TypeDeclaration classType = ast.newTypeDeclaration();
classType.setInterface(false);
List classTypeModifier = classType.modifiers();
classTypeModifier.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
classType.setName(ast.newSimpleName("MyFirstApp"));
classType.setSuperclassType(ast.newSimpleType(ast.newSimpleName("ApplicationWindow")));
unit.types().add(classType);
這裏爲指定生成文件的類型,可以在這裏指定生成類的名稱,是生成的是否是接口,還有訪問類型,結果是 public class MyFirstApp extends ApplicationWindow {
MethodDeclaration methodConstructor = ast.newMethodDeclaration();
methodConstructor.setConstructor(true);
List methodConstructorModifier = methodConstructor.modifiers();
methodConstructorModifier.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
methodConstructor.setName(ast.newSimpleName("MyFirstApp"));
classType.bodyDeclarations().add(methodConstructor);
上面爲生成一個方法,並指定這個方法是構造方法,生成結果是 public MyFirstApp(){
哎,算了,這樣太費勁了,下面是程序的代碼
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.AnonymousClassDeclaration;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jdt.core.dom.ImportDeclaration;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.PackageDeclaration;
import org.eclipse.jdt.core.dom.PrimitiveType;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.SingleVariableDeclaration;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.SuperConstructorInvocation;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
import org.eclipse.jdt.core.dom.Modifier.ModifierKeyword;
import com.vwpolo.jet.example.JavaASTParserExample9.CompilationUnitImpl;
public class JavaASTParserExample1 {
private static final String[] IMPORTS = { "org.eclipse.jface.action.*", "org.eclipse.jface.window.*","org.eclipse.swt.events.*",
"org.eclipse.swt.*","org.eclipse.jface.dialogs.*", "org.eclipse.swt.graphics.*", "org.eclipse.swt.widgets.*" };
@SuppressWarnings("unchecked")
public static void main(String[] args) {
CompilationUnit unit = getCompilationUtil();
System.out.println(unit.toString());
JavaASTParserExample9.compileAndRun(new CompilationUnitImpl(unit));
}
@SuppressWarnings("unchecked")
private static CompilationUnit getCompilationUtil() {
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource("".toCharArray());
CompilationUnit unit = (CompilationUnit) parser.createAST(null);
unit.recordModifications();
AST ast = unit.getAST();
PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
unit.setPackage(packageDeclaration);
packageDeclaration.setName(ast.newSimpleName("astdemo"));
for (int i = 0; i < IMPORTS.length; ++i) {
ImportDeclaration importDeclaration = ast.newImportDeclaration();
importDeclaration.setName(ast.newName(getSimpleNames(IMPORTS[i])));
if (IMPORTS[i].indexOf("*") > 0)
importDeclaration.setOnDemand(true);
else
importDeclaration.setOnDemand(false);
unit.imports().add(importDeclaration);
}
//類名
TypeDeclaration classType = ast.newTypeDeclaration();
classType.setInterface(false);
List classTypeModifier = classType.modifiers();
classTypeModifier.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
classType.setName(ast.newSimpleName("MyFirstApp"));
classType.setSuperclassType(ast.newSimpleType(ast.newSimpleName("ApplicationWindow")));
unit.types().add(classType);
//構造方法
MethodDeclaration methodConstructor = ast.newMethodDeclaration();
methodConstructor.setConstructor(true);
List methodConstructorModifier = methodConstructor.modifiers();
methodConstructorModifier.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
methodConstructor.setName(ast.newSimpleName("MyFirstApp"));
classType.bodyDeclarations().add(methodConstructor);
Block constructorBlock = ast.newBlock();
methodConstructor.setBody(constructorBlock);
//super(null);
SuperConstructorInvocation superConstructorInvocation = ast.newSuperConstructorInvocation();
constructorBlock.statements().add(superConstructorInvocation);
superConstructorInvocation.arguments().add(ast.newNullLiteral());
//createActions();
MethodInvocation methodInvocation = ast.newMethodInvocation();
methodInvocation.setName(ast.newSimpleName("createActions"));
constructorBlock.statements().add(ast.newExpressionStatement(methodInvocation));
//addToolBar(SWT.FLAT | SWT.WRAP);
MethodInvocation methodInvocation2 = ast.newMethodInvocation();
methodInvocation2.setName(ast.newSimpleName("addToolBar"));
InfixExpression infixExpression = ast.newInfixExpression();
infixExpression.setOperator(Operator.OR);
infixExpression.setLeftOperand(ast.newName(getSimpleNames("SWT.FLAT")));
infixExpression.setRightOperand(ast.newName(getSimpleNames("SWT.WRAP")));
methodInvocation2.arguments().add(infixExpression);
constructorBlock.statements().add(ast.newExpressionStatement(methodInvocation2));
//addMenuBar();
MethodInvocation methodInvocation3 = ast.newMethodInvocation();
methodInvocation3.setName(ast.newSimpleName("addMenuBar"));
constructorBlock.statements().add(ast.newExpressionStatement(methodInvocation3));
//addStatusLine();
MethodInvocation methodInvocation4 = ast.newMethodInvocation();
methodInvocation4.setName(ast.newSimpleName("addStatusLine"));
constructorBlock.statements().add(ast.newExpressionStatement(methodInvocation4));
MethodDeclaration methodDeclaration = ast.newMethodDeclaration();
methodDeclaration.setConstructor(false);
List methodModifiers = methodDeclaration.modifiers();
methodModifiers.add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD));
methodDeclaration.setReturnType2(ast.newSimpleType(ast.newSimpleName("Control")));
methodDeclaration.setName(ast.newSimpleName("createContents"));
classType.bodyDeclarations().add(methodDeclaration);
Block methodBlock = ast.newBlock();
methodDeclaration.setBody(methodBlock);
// createContents(Composite parent) {
SingleVariableDeclaration variableDeclaration = ast.newSingleVariableDeclaration();
variableDeclaration.setType(ast.newSimpleType(ast.newSimpleName("Composite")));
variableDeclaration.setName(ast.newSimpleName("parent"));
methodDeclaration.parameters().add(variableDeclaration);
// Composite container = new Composite(parent, SWT.NONE);
VariableDeclarationFragment variableFragment = ast.newVariableDeclarationFragment();
variableFragment.setName(ast.newSimpleName("container"));
VariableDeclarationStatement variableStatement = ast.newVariableDeclarationStatement(variableFragment);
variableStatement.setType(ast.newSimpleType(ast.newSimpleName("Composite")));
ClassInstanceCreation classCreation = ast.newClassInstanceCreation();
classCreation.setType(ast.newSimpleType(ast.newSimpleName("Composite")));
variableFragment.setInitializer(classCreation);
methodBlock.statements().add(variableStatement);
classCreation.arguments().add(ast.newSimpleName("parent"));
classCreation.arguments().add(ast.newName(getSimpleNames("SWT.NONE")));
//final Button button = new Button(container, SWT.NONE);
VariableDeclarationFragment variableFragment2 = ast.newVariableDeclarationFragment();
variableFragment2.setName(ast.newSimpleName("button"));
VariableDeclarationStatement variableStatement2 = ast.newVariableDeclarationStatement(variableFragment2);
List variableModifier2 = variableStatement2.modifiers();
variableModifier2.add(ast.newModifier(ModifierKeyword.FINAL_KEYWORD));
variableStatement2.setType(ast.newSimpleType(ast.newSimpleName("Button")));
ClassInstanceCreation classCreation2 = ast.newClassInstanceCreation();
classCreation2.setType(ast.newSimpleType(ast.newSimpleName("Button")));
variableFragment2.setInitializer(classCreation2);
methodBlock.statements().add(variableStatement2);
classCreation2.arguments().add(ast.newSimpleName("container"));
classCreation2.arguments().add(ast.newName(getSimpleNames("SWT.NONE")));
// button.addSelectionListener(new SelectionAdapter() {});
MethodInvocation methodInvocation5 = ast.newMethodInvocation();
methodBlock.statements().add(ast.newExpressionStatement(methodInvocation5));
methodInvocation5.setExpression(ast.newSimpleName("button"));
methodInvocation5.setName(ast.newSimpleName("addSelectionListener"));
ClassInstanceCreation ci = ast.newClassInstanceCreation();
ci.setType(ast.newSimpleType(ast.newSimpleName("SelectionAdapter")));
methodInvocation5.arguments().add(ci);
AnonymousClassDeclaration cd = ast.newAnonymousClassDeclaration();
ci.setAnonymousClassDeclaration(cd);
// public void widgetSelected(SelectionEvent e) {
MethodDeclaration md = ast.newMethodDeclaration();
md.setConstructor(false);
List mdModifiers = md.modifiers();
mdModifiers.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
md.setName(ast.newSimpleName("widgetSelected"));
cd.bodyDeclarations().add(md);
SingleVariableDeclaration variableDeclaration2 = ast.newSingleVariableDeclaration();
variableDeclaration2.setType(ast.newSimpleType(ast.newSimpleName("SelectionEvent")));
variableDeclaration2.setName(ast.newSimpleName("e"));
md.parameters().add(variableDeclaration2);
Block methodBlock2 = ast.newBlock();
md.setBody(methodBlock2);
MethodInvocation methodInvocation6 = ast.newMethodInvocation();
methodInvocation6.setExpression(ast.newSimpleName("MessageDialog"));
methodInvocation6.setName(ast.newSimpleName("openInformation"));
MethodInvocation methodInvocation12 = ast.newMethodInvocation();
methodInvocation12.setName(ast.newSimpleName("getShell"));
methodInvocation6.arguments().add(methodInvocation12);
StringLiteral stringLiteral1 = ast.newStringLiteral();
stringLiteral1.setEscapedValue(""信息"");
StringLiteral stringLiteral2 = ast.newStringLiteral();
stringLiteral2.setEscapedValue(""你好"");
methodInvocation6.arguments().add(stringLiteral1);
methodInvocation6.arguments().add(stringLiteral2);
methodBlock2.statements().add(ast.newExpressionStatement(methodInvocation6));
MethodInvocation methodInvocation7 = ast.newMethodInvocation();
methodInvocation7.setExpression(ast.newSimpleName("button"));
methodInvocation7.setName(ast.newSimpleName("setText"));
StringLiteral stringLiteral3 = ast.newStringLiteral();
stringLiteral3.setEscapedValue(""按 鈕"");
methodInvocation7.arguments().add(stringLiteral3);
methodBlock.statements().add(ast.newExpressionStatement(methodInvocation7));
// button.setText("按 鈕");
MethodInvocation methodInvocation8 = ast.newMethodInvocation();
methodInvocation8.setExpression(ast.newSimpleName("button"));
methodInvocation8.setName(ast.newSimpleName("setBounds"));
StringLiteral stringLiteral4 = ast.newStringLiteral();
stringLiteral4.setEscapedValue(""按 鈕"");
//button.setBounds(69, 28, 44, 23);
methodInvocation8.arguments().add(ast.newNumberLiteral("69"));
methodInvocation8.arguments().add(ast.newNumberLiteral("28"));
methodInvocation8.arguments().add(ast.newNumberLiteral("44"));
methodInvocation8.arguments().add(ast.newNumberLiteral("23"));
methodBlock.statements().add(ast.newExpressionStatement(methodInvocation8));
//return container;
ReturnStatement returnStatement = ast.newReturnStatement();
returnStatement.setExpression(ast.newSimpleName("container"));
methodBlock.statements().add(returnStatement);
//private void createActions()
MethodDeclaration methodDeclaration2 = ast.newMethodDeclaration();
methodDeclaration2.setConstructor(false);
List methodModifiers2 = methodDeclaration2.modifiers();
methodModifiers2.add(ast.newModifier(ModifierKeyword.PRIVATE_KEYWORD));
methodDeclaration2.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID));
methodDeclaration2.setName(ast.newSimpleName("createActions"));
Block methodBlock3 = ast.newBlock();
methodDeclaration2.setBody(methodBlock3);
classType.bodyDeclarations().add(methodDeclaration2);
// protected MenuManager createMenuManager()
MethodDeclaration methodDeclaration3 = ast.newMethodDeclaration();
methodDeclaration3.setConstructor(false);
List methodModifiers3 = methodDeclaration3.modifiers();
methodModifiers3.add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD));
methodDeclaration3.setReturnType2(ast.newSimpleType(ast.newName("MenuManager")));
methodDeclaration3.setName(ast.newSimpleName("createMenuManager"));
Block methodBlock4 = ast.newBlock();
methodDeclaration3.setBody(methodBlock4);
classType.bodyDeclarations().add(methodDeclaration3);
//MenuManager menuManager = new MenuManager("menu");
VariableDeclarationFragment variableFragment3 = ast.newVariableDeclarationFragment();
variableFragment3.setName(ast.newSimpleName("menuManager"));
VariableDeclarationStatement variableStatement3 = ast.newVariableDeclarationStatement(variableFragment3);
variableStatement3.setType(ast.newSimpleType(ast.newSimpleName("MenuManager")));
ClassInstanceCreation classCreation3 = ast.newClassInstanceCreation();
classCreation3.setType(ast.newSimpleType(ast.newSimpleName("MenuManager")));
StringLiteral stringLiteral5 = ast.newStringLiteral();
stringLiteral5.setEscapedValue(""menu"");
classCreation3.arguments().add(stringLiteral5);
variableFragment3.setInitializer(classCreation3);
methodBlock4.statements().add(variableStatement3);
// return menuManager;
ReturnStatement returnStatement2 = ast.newReturnStatement();
returnStatement2.setExpression(ast.newSimpleName("menuManager"));
methodBlock4.statements().add(returnStatement2);
// protected ToolBarManager createToolBarManager(int style) {
MethodDeclaration methodDeclaration4 = ast.newMethodDeclaration();
methodDeclaration4.setConstructor(false);
List methodModifiers4 = methodDeclaration4.modifiers();
methodModifiers4.add(ast.newModifier(ModifierKeyword.PROTECTED_KEYWORD));
methodDeclaration4.setReturnType2(ast.newSimpleType(ast.newName("ToolBarManager")));
methodDeclaration4.setName(ast.newSimpleName("createToolBarManager"));
SingleVariableDeclaration variableDeclaration5 = ast.newSingleVariableDeclaration();
variableDeclaration5.setType(ast.newPrimitiveType(PrimitiveType.INT));
variableDeclaration5.setName(ast.newSimpleName("style"));
methodDeclaration4.parameters().add(variableDeclaration5);
Block methodBlock5 = ast.newBlock();
methodDeclaration4.setBody(methodBlock5);
classType.bodyDeclarations().add(methodDeclaration4);
//MenuManager menuManager = new MenuManager("menu");
VariableDeclarationFragment variableFragment4 = ast.newVariableDeclarationFragment();
variableFragment4.setName(ast.newSimpleName("toolBarManager"));
VariableDeclarationStatement variableStatement4 = ast.newVariableDeclarationStatement(variableFragment4);
variableStatement4.setType(ast.newSimpleType(ast.newSimpleName("ToolBarManager")));
ClassInstanceCreation classCreation4 = ast.newClassInstanceCreation();
classCreation4.setType(ast.newSimpleType(ast.newSimpleName("ToolBarManager")));
StringLiteral stringLiteral6 = ast.newStringLiteral();
stringLiteral6.setEscapedValue(""menu"");
classCreation3.arguments().add(stringLiteral6);
variableFragment4.setInitializer(classCreation4);
methodBlock5.statements().add(variableStatement4);
// toolBarManager
ReturnStatement returnStatement3 = ast.newReturnStatement();
returnStatement3.setExpression(ast.newSimpleName("toolBarManager"));
methodBlock5.statements().add(returnStatement3);
MethodDeclaration mainMethod = ast.newMethodDeclaration();
mainMethod.setConstructor(false);
List mainMethodModifiers = mainMethod.modifiers();
mainMethodModifiers.add(ast.newModifier(ModifierKeyword.PUBLIC_KEYWORD));
mainMethodModifiers.add(ast.newModifier(ModifierKeyword.STATIC_KEYWORD));
mainMethod.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID));
mainMethod.setName(ast.newSimpleName("main"));
Block mainBlock = ast.newBlock();
mainMethod.setBody(mainBlock);
SingleVariableDeclaration mainSingleVariable = ast.newSingleVariableDeclaration();
mainSingleVariable.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName("String"))));
mainSingleVariable.setName(ast.newSimpleName("args"));
mainMethod.parameters().add(mainSingleVariable);
classType.bodyDeclarations().add(mainMethod);
VariableDeclarationFragment variableFragment5 = ast.newVariableDeclarationFragment();
variableFragment5.setName(ast.newSimpleName("window"));
VariableDeclarationStatement variableStatement5 = ast.newVariableDeclarationStatement(variableFragment5);
variableStatement5.setType(ast.newSimpleType(ast.newSimpleName("MyFirstApp")));
ClassInstanceCreation classCreation5 = ast.newClassInstanceCreation();
classCreation5.setType(ast.newSimpleType(ast.newSimpleName("MyFirstApp")));
variableFragment5.setInitializer(classCreation5);
mainBlock.statements().add(variableStatement5);
// window.setBlockOnOpen(true);
MethodInvocation methodInvocation9 = ast.newMethodInvocation();
methodInvocation9.setExpression(ast.newSimpleName("window"));
methodInvocation9.setName(ast.newSimpleName("setBlockOnOpen"));
methodInvocation9.arguments().add(ast.newBooleanLiteral(true));
mainBlock.statements().add(ast.newExpressionStatement(methodInvocation9));
// window.setBlockOnOpen(true);
MethodInvocation methodInvocation10 = ast.newMethodInvocation();
methodInvocation10.setExpression(ast.newSimpleName("window"));
methodInvocation10.setName(ast.newSimpleName("open"));
mainBlock.statements().add(ast.newExpressionStatement(methodInvocation10));
//Display.getCurrent().dispose();
// MethodInvocation methodInvocation11 = ast.newMethodInvocation();
// methodInvocation11.setExpression(ast.newName(getSimpleNames("Display.getCurrent()")));
// methodInvocation11.setName(ast.newSimpleName("dispose"));
// mainBlock.statements().add(ast.newExpressionStatement(methodInvocation11));
return unit;
}
@SuppressWarnings("unchecked")
static private String[] getSimpleNames(String qualifiedName) {
StringTokenizer st = new StringTokenizer(qualifiedName, ".");
ArrayList list = new ArrayList();
while (st.hasMoreTokens()) {
String name = st.nextToken().trim();
if (!name.equals("*"))
list.add(name);
}
return (String[]) list.toArray(new String[list.size()]);
}
}