メソッドの実装
まずはじめに、プラグインプロジェクトを作成する。次に、必須プラグインに以下のプラグインを追加する。
プラグイン | 使用するクラス |
---|---|
org.eclipse.core.resources | IFile |
org.eclipse.jdt.core |
ICompilationUnit JavaCore AST ASTParser ASTVisitor CompilationUnit
|
org.eclipse.jface.text |
BadLocationException IDocument MalformedTreeException TextEdit
|
org.eclipse.ui.editors | ITextEditor |
org.eclipse.ui.ide | IFileEditorInput |
最後に、以下のインポート宣言とメソッド定義を適切な場所に記述する。
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.resources.IFile;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.text.edits.MalformedTreeException;
import org.eclipse.text.edits.TextEdit;
import org.eclipse.ui.IFileEditorInput;
import org.eclipse.ui.handlers.HandlerUtil;
import org.eclipse.ui.texteditor.ITextEditor;
public void manipulateJavaSource(ExecutionEvent event, ASTVisitor visitor) {
ITextEditor editor = (ITextEditor)HandlerUtil.getActiveEditor(event);
IFileEditorInput input = (IFileEditorInput)editor.getEditorInput();
IDocument document = editor.getDocumentProvider().getDocument(input);
IFile file = input.getFile();
ICompilationUnit source = JavaCore.createCompilationUnitFrom(file);
ASTParser parser = ASTParser.newParser(AST.JLS8);
parser.setSource(source);
CompilationUnit root = (CompilationUnit)parser.createAST(null);
root.recordModifications();
root.accept(visitor);
TextEdit textEdit = root.rewrite(document, null);
try {
textEdit.apply(document);
} catch (BadLocationException | MalformedTreeException e) {
throw new RuntimeException(e);
}
}
メソッドの概要
- エディタがテキストエディタでない場合は、例外が発生して異常終了する。
- エディタの編集対象がJavaファイルでない場合は、例外が発生して異常終了する。
使用例:ゲッターとセッターの生成
変更前
public class Student {
private int id;
private String name;
private int age;
}
変更後
public class Student {
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
実装部(インポート宣言)
import org.apache.commons.lang3.StringUtils;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.commands.ExecutionException;
import org.eclipse.jdt.core.dom.*;
実装部(イベントハンドラ)
public Object execute(ExecutionEvent event) throws ExecutionException {
manipulateJavaSource(event, new CreatePropertyVisitor());
return null;
}
実装部(Visitor定義)
private class CreatePropertyVisitor extends ASTVisitor {
@Override
public boolean visit(FieldDeclaration node) {
TypeDeclaration parent = (TypeDeclaration)node.getParent();
AST ast = parent.getAST();
VariableDeclarationFragment var = (VariableDeclarationFragment)node.fragments().get(0);
String name = var.getName().getIdentifier();
// public Type getProperty() {
// return property;
// }
MethodDeclaration getter = ast.newMethodDeclaration();
{
// public
getter.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
// Type
getter.setReturnType2((Type)ASTNode.copySubtree(ast, node.getType()));
// getProperty
getter.setName(ast.newSimpleName("get" + StringUtils.capitalize(name)));
// {
Block block = ast.newBlock();
{
// return property;
ReturnStatement returnStatement = ast.newReturnStatement();
{
returnStatement.setExpression(ast.newSimpleName(name));
}
block.statements().add(returnStatement);
}
getter.setBody(block);
// }
}
// public void setProperty(Type property) {
// this.property = property;
// }
MethodDeclaration setter = ast.newMethodDeclaration();
{
// public
setter.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
// setProperty
setter.setName(ast.newSimpleName("set" + StringUtils.capitalize(name)));
// (Type property)
SingleVariableDeclaration singleVariable = ast.newSingleVariableDeclaration();
singleVariable.setType((Type)ASTNode.copySubtree(ast, node.getType()));
singleVariable.setName(ast.newSimpleName(name));
setter.parameters().add(singleVariable);
// {
Block block = ast.newBlock();
{
// this.property = property;
Assignment assignment = ast.newAssignment();
{
// this.field
FieldAccess fieldAccess = ast.newFieldAccess();
fieldAccess.setExpression(ast.newThisExpression());
fieldAccess.setName(ast.newSimpleName(name));
assignment.setLeftHandSide(fieldAccess);
// =
assignment.setOperator(Assignment.Operator.ASSIGN);
// field
assignment.setRightHandSide(ast.newSimpleName(name));
}
block.statements().add(ast.newExpressionStatement(assignment));
}
setter.setBody(block);
// }
}
parent.bodyDeclarations().add(getter);
parent.bodyDeclarations().add(setter);
return super.visit(node);
}
}
-
singleVariable.setType(node.getType())
はエラーになる。これは、node.getType()
によって得られるType
オブジェクトはnode
オブジェクトの子ノードであり、ノードは複数の親を持つことができないため。singleVariable.setType()
によって設定できるのは、親を持たないノードのみ。ASTNode.copySubtree()
によって複製されたノードは親を持たないため、singleVariable.setType()
に渡してもエラーにならない。 -
visit()
のブロック内でFieldDeclaration
オブジェクトを追加した場合は無限ループとなる。 - AST Viewを使うことで、Javaソースコードの抽象構文木を視覚的に捉えることができる。更に各ノードのクラスの名前がわかるため、Visitorを作るときには必須のプラグインといってよい。