Version 1.6
Copyright © 2009, 2010, 2011, 2012 Lars Vogel
08.08.2012
| Revision History | |||
|---|---|---|---|
| Revision 0.1 | 11.05.2009 | Lars Vogel |
created |
| Revision 0.2 - 1.6 | 23.05.2009 - 08.08.2012 | Lars Vogel |
bugfixes and enhancements |
Table of Contents
The Eclipse Java Development Tools (JDT) provide APIs to access and manipulate Java source code. It allows to access the existing projects in the workspace, create new projects and modify and read existing projects. It also allows to launch Java programs.
JDT allows to access Java source code via two different means. The Java Model and the Abstract Syntax Tree (AST) which is a Document Object Model similar to the XML DOM.
Each Java project is internally represented in Eclipse as a Java model. The Eclipse Java model is a light-weight and fault tolerant representation of the Java project.
It does not contain as many information as the Abstract Syntax Tree (AST) but is fast to create. For example the Outline view is using the Java model for its representation; this way the information in the Outline view can quickly get updated.
The Java model is defined in the
org.eclipse.jdt.core
plug-in.
The Java model is represented as a tree structure which can be described via the following table.
Table 1.
| Project Element | Java Model element | Description |
|---|---|---|
| Java project | IJavaProject | The Java project which contains all other objects. |
| src folder / bin folder / or external library | IPackageFragmentRoot | Hold source or binary files, can be a folder or a library (zip / jar file) |
| Each package | IPackageFragment | Each package is below the IPackageFragmentRoot, sub-packages are not leaves of the package, they are listed directed under IPackageFragmentRoot |
| Java Source File | ICompilationUnit | The Source file is always below the package node |
| Types / Fields / Methods | IType / IField / IMethod | Types, fields and methods |
The AST is a detailed tree representation of the Java source code. The AST defines API to modify, create, read and delete source code.
The main package for the AST is called
org.eclipse.jdt.core.dom
and is located in the
org.eclipse.jdt.core
plug-in.
Each Java source file is represented as a
subclass of
the
ASTNode
class. Each specific AST node provides specific
information about the
object it represents. For example you have
MethodDeclaration
(for
methods),
VariableDeclarationFragment
(for variable declarations) and
SimpleName
(for any string which is not a Java keyword).
The AST is typically created based on a
ICompilationUnit
from the Java Model.
This article assume that you are familiar with Eclipse plug-in development. See Eclipse Plugin Development for an introduction. For user interface related activities, e.g. creating a view extension point please see Eclipse RCP tutorial.
The following will create a command which will read the project of the workspace, get all package and Java source files for these projects and read all methods for them by using the JDT Java Model API.
Create a plug-in project called
de.vogella.jdt.infos. Choose
the
"Hello World, command" as a template.
Add the following dependencies to your plug-in:
org.eclipse.core.resources
org.eclipse.jdt
org.eclipse.jdt.core
org.eclipse.core.runtime
org.eclipse.jdt.ui
org.eclipse.jface.text
Change the handler to the following.
package de.vogella.jdt.infos.handlers; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jface.text.Document; public class SampleHandler extends AbstractHandler { public Object execute(ExecutionEvent event) throws ExecutionException { // Get the root of the workspace IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); // Get all projects in the workspace IProject[] projects = root.getProjects(); // Loop over all projects for (IProject project : projects) { try { printProjectInfo(project); } catch (CoreException e) { e.printStackTrace(); } } return null; } private void printProjectInfo(IProject project) throws CoreException, JavaModelException { System.out.println("Working in project " + project.getName()); // Check if we have a Java project if (project.isNatureEnabled("org.eclipse.jdt.core.javanature")) { IJavaProject javaProject = JavaCore.create(project); printPackageInfos(javaProject); } } private void printPackageInfos(IJavaProject javaProject) throws JavaModelException { IPackageFragment[] packages = javaProject.getPackageFragments(); for (IPackageFragment mypackage : packages) { // Package fragments include all packages in the // classpath // We will only look at the package from the source // folder // K_BINARY would include also included JARS, e.g. // rt.jar if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) { System.out.println("Package " + mypackage.getElementName()); printICompilationUnitInfo(mypackage); } } } private void printICompilationUnitInfo(IPackageFragment mypackage) throws JavaModelException { for (ICompilationUnit unit : mypackage.getCompilationUnits()) { printCompilationUnitDetails(unit); } } private void printIMethods(ICompilationUnit unit) throws JavaModelException { IType[] allTypes = unit.getAllTypes(); for (IType type : allTypes) { printIMethodDetails(type); } } private void printCompilationUnitDetails(ICompilationUnit unit) throws JavaModelException { System.out.println("Source file " + unit.getElementName()); Document doc = new Document(unit.getSource()); System.out.println("Has number of lines: " + doc.getNumberOfLines()); printIMethods(unit); } private void printIMethodDetails(IType type) throws JavaModelException { IMethod[] methods = type.getMethods(); for (IMethod method : methods) { System.out.println("Method name " + method.getElementName()); System.out.println("Signature " + method.getSignature()); System.out.println("Return Type " + method.getReturnType()); } } }
Start your plug-in. Create a few projects in your new workspace. Create a few packages for them and a few Java files. Press the menu entry which points to your sample command.
You should see the projects, package and source files listed in the Console view of the calling workbench.
The following will create a command which will create a new package to existing (and open) Java projects which have the same name as the Java project. For example if you have a project "de.vogella.test" in your workspace without any package this command will create the package "de.vogella.test" in this project.
Create a new plug-in project "de.vogella.jdt.newelements".
Add a new command "de.vogella.jdt.newelements.AddPackage" and put it into the menu.
Create the following handler for this command.
package de.vogella.jdt.newelements.handler; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; public class AddPackage extends AbstractHandler { @Override public Object execute(ExecutionEvent event) throws ExecutionException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); // Get all projects in the workspace IProject[] projects = root.getProjects(); // Loop over all projects for (IProject project : projects) { try { // Only work on open projects with the Java nature if (project.isOpen() & project.isNatureEnabled(JavaCore.NATURE_ID)) { createPackage(project); } } catch (CoreException e) { e.printStackTrace(); } return null; } private void createPackage(IProject project) throws JavaModelException { IJavaProject javaProject = JavaCore.create(project); IFolder folder = project.getFolder("src"); // folder.create(true, true, null); IPackageFragmentRoot srcFolder = javaProject .getPackageFragmentRoot(folder); IPackageFragment fragment = srcFolder.createPackageFragment(project.getName(), true, null); } }
An example can be found on the source page in project "de.vogella.jdt.packageexplorer". Have a look at the command handler "AddPackage.java".
You can also modify the classpath of your project. The following example handler is contained in project "de.vogella.jdt.addclasspath". It will add JUnit4 to the classpath of your project.
package de.vogella.jdt.addclasspath.handlers; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.JavaCore; public class SampleHandler extends AbstractHandler { private static final String JDT_NATURE = "org.eclipse.jdt.core.javanature"; public Object execute(ExecutionEvent event) throws ExecutionException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); // Get all projects in the workspace IProject[] projects = root.getProjects(); // Loop over all projects for (IProject project : projects) { try { // Only work on open projects with the Java nature if (project.isOpen() && project.isNatureEnabled(JDT_NATURE)) { changeClassPath(project); } } catch (CoreException e) { e.printStackTrace(); } } return null; } private void changeClasspath(IProject project) throws JavaModelException { IJavaProject javaProject = JavaCore.create(project); IClasspathEntry[] entries = javaProject.getRawClasspath(); IClasspathEntry[] newEntries = new IClasspathEntry[entries.length + 1]; System.arraycopy(entries, 0, newEntries, 0, entries.length); // add a new entry using the path to the container Path junitPath = new Path("org.eclipse.jdt.junit.JUNIT_CONTAINER/4"); IClasspathEntry junitEntry = JavaCore .newContainerEntry(junitPath); newEntries[entries.length] = JavaCore .newContainerEntry(junitEntry.getPath()); javaProject.setRawClasspath(newEntries, null); } }
The following will create an AST for each source file in your workspace and print out the name and the return type of each method using the AST.
Create a new plug-in project "de.vogella.jdt.astsimple" using the "Hello world" template.
Maintain the following plug-in dependencies.
Manifest-Version: 1.0 Bundle-ManifestVersion: 2 Bundle-Name: Astsimple Plug-in Bundle-SymbolicName: de.vogella.jdt.astsimple;singleton:=true Bundle-Version: 1.0.0 Bundle-RequiredExecutionEnvironment: JavaSE-1.6 Require-Bundle: org.eclipse.core.runtime;bundle-version="3.4.0", org.eclipse.ui;bundle-version="3.4.2", org.eclipse.jdt.core;bundle-version="3.4.4", org.eclipse.core.resources;bundle-version="3.4.2", org.eclipse.jdt.ui;bundle-version="3.4.2"
To get information about the AST you can use the Visitor Pattern. This allows you to add a visitor to the AST for a specific elements. In this visitor can you capture information about the object and return it after processing the AST. Create for this the following class.
package de.vogella.jdt.astsimple.handler; import java.util.ArrayList; import java.util.List; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.MethodDeclaration; public class MethodVisitor extends ASTVisitor { List<MethodDeclaration> methods = new ArrayList<MethodDeclaration>(); @Override public boolean visit(MethodDeclaration node) { methods.add(node); return super.visit(node); } public List<MethodDeclaration> getMethods() { return methods; } }
Add a new command "de.vogella.jdt.astsimple.GetInfo" and put it into the menu.
Create the following handler for this command.
package de.vogella.jdt.astsimple.handler; import org.eclipse.core.commands.AbstractHandler; import org.eclipse.core.commands.ExecutionEvent; import org.eclipse.core.commands.ExecutionException; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IWorkspace; import org.eclipse.core.resources.IWorkspaceRoot; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.dom.AST; import org.eclipse.jdt.core.dom.ASTParser; import org.eclipse.jdt.core.dom.CompilationUnit; import org.eclipse.jdt.core.dom.MethodDeclaration; public class GetInfo extends AbstractHandler { private static final String JDT_NATURE = "org.eclipse.jdt.core.javanature"; @Override public Object execute(ExecutionEvent event) throws ExecutionException { IWorkspace workspace = ResourcesPlugin.getWorkspace(); IWorkspaceRoot root = workspace.getRoot(); // Get all projects in the workspace IProject[] projects = root.getProjects(); // Loop over all projects for (IProject project : projects) { try { if (project.isNatureEnabled(JDT_NATURE)) { analyseMethods(project); } } catch (CoreException e) { e.printStackTrace(); } } return null; } private void analyseMethods(IProject project) throws JavaModelException { IPackageFragment[] packages = JavaCore.create(project) .getPackageFragments(); // parse(JavaCore.create(project)); for (IPackageFragment mypackage : packages) { if (mypackage.getKind() == IPackageFragmentRoot.K_SOURCE) { createAST(mypackage); } } } private void createAST(IPackageFragment mypackage) throws JavaModelException { for (ICompilationUnit unit : mypackage.getCompilationUnits()) { // Now create the AST for the ICompilationUnits CompilationUnit parse = parse(unit); MethodVisitor visitor = new MethodVisitor(); parse.accept(visitor); for (MethodDeclaration method : visitor.getMethods()) { System.out.print("Method name: " + method.getName() + " Return type: " + method.getReturnType2()); } } }/** * Reads a ICompilationUnit and creates the AST DOM for manipulating the * Java source file * * @param unit * @return */private static CompilationUnit parse(ICompilationUnit unit) { ASTParser parser = ASTParser.newParser(AST.JLS3); parser.setKind(ASTParser.K_COMPILATION_UNIT); parser.setSource(unit); parser.setResolveBindings(true); return (CompilationUnit) parser.createAST(null); // parse } }
Add the command to your menu. Run your new plugin, create a new Java project and select the command. It should print out the information about your methods in the IDE from which you started your new plugin
Before posting questions, please see the vogella FAQ. If you have questions or find an error in this article please use the www.vogella.com Google Group. I have created a short list how to create good questions which might also help you.
http://www.eclipsecon.org/2005/presentations/EclipseCON2005_Tutorial29.pdf Presentation about using Eclipse JDT
Creating Java projects with JDT API
http://www.eclipse.org/articles/article.php?file=Article-JavaCodeManipulation_AST/index.html Java Code Manipulation AST
http://www.eclipse.org/articles/article.php?file=Article-Unleashing-the-Power-of-Refactoring/index.html Article about using the JDT Refactoring API
http://www.ibm.com/developerworks/opensource/library/os-ast/ IBM Article about the AST
vogella Training Android and Eclipse Training from the vogella team
Android Tutorial Introduction to Android Programming
GWT Tutorial Program in Java and compile to JavaScript and HTML
Eclipse RCP Tutorial Create native applications in Java
JUnit Tutorial Test your application
Git Tutorial Put everything you have under distributed version control system