blob: a4fea09a14e32cb20d578382cf9778b8e636d6b9 [file] [log] [blame]
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta name="copyright" content=
"Copyright (c) IBM Corporation and others 2000, 2011. This page is made available under license. For full details see the LEGAL in the documentation book that contains this page." />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta http-equiv="Content-Style-Type" content="text/css" />
<link rel="STYLESHEET" href="../book.css" charset="ISO-8859-1" type="text/css" />
<title>Manipulating Java code</title>
<link rel="stylesheet" type="text/css" href="../book.css" />
</head>
<body>
<h2>Manipulating Java code</h2>
<p>Your plug-in can use the JDT API to create classes or interfaces, add methods to existing types,
or alter the methods for types.</p>
<p>The simplest way to alter Java objects is to use the Java element API. More general techniques
can be used to work with the raw source code for a Java element.</p>
<h3>Code modification using Java elements</h3>
<h4>Generating a compilation unit</h4>
<p>The easiest way to programmatically generate a compilation unit is to use <b><a href=
"../reference/api/org/eclipse/jdt/core/IPackageFragment.html#createCompilationUnit(java.lang.String,%20java.lang.String,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
IPackageFragment.createCompilationUnit</a></b>. You specify the name and contents of the
compilation unit. The compilation unit is created inside the package and the new <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html">ICompilationUnit</a></b> is
returned.</p>
<p>A compilation unit can be created generically by creating a file resource whose extension is
"<b>.java"</b> in the appropriate folder that corresponds to the package directory. Using the
generic resource API is a back door to the Java tooling, so the Java model is not updated until the
generic resource change listeners are notified and the JDT listeners update the Java model with the
new compilation unit.</p>
<h4>Modifying a compilation unit</h4>
<p>Most simple modifications of Java source can be done using the Java element API.</p>
<p>For example, you can query a type from a compilation unit. Once you have the <a href=
"../reference/api/org/eclipse/jdt/core/IType.html"><b>IType</b></a>, you can use protocols such as
<a href=
"../reference/api/org/eclipse/jdt/core/IType.html#createField(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>createField</b></a>, <a href=
"../reference/api/org/eclipse/jdt/core/IType.html#createInitializer(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>createInitializer</b></a>, <a href=
"../reference/api/org/eclipse/jdt/core/IType.html#createMethod(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>createMethod</b></a>, or <a href=
"../reference/api/org/eclipse/jdt/core/IType.html#createType(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>createType</b></a> to add source code members to the type. The source code and information about
the location of the member is supplied in these methods.</p>
<p>The <b><a href=
"../reference/api/org/eclipse/jdt/core/ISourceManipulation.html">ISourceManipulation</a></b>
interface defines common source manipulations for Java elements. This includes methods for
renaming, moving, copying, or deleting a type's member.</p>
<h4>Working copies</h4>
<p>Code can be modified by manipulating the compilation unit (and thus the underlying <a href=
"../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IFile.html"><b>IFile</b></a>
is modified) or one can modify an in-memory copy of the compilation unit called a working copy.</p>
<p>A working copy is obtained from a compilation unit using the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#getWorkingCopy(org.eclipse.core.runtime.IProgressMonitor)">
getWorkingCopy</a></b> method. (Note that the compilation unit does not need to exist in the Java
model in order for a working copy to be created.)&nbsp; Whoever creates such a working copy is
responsible for discarding it when not needed any longer using the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#discardWorkingCopy()">discardWorkingCopy</a></b>
method.</p>
<p>Working copies modify an in-memory buffer. The <b>getWorkingCopy()</b> method creates a default
buffer, but clients can provide their own buffer implementation using the <b><a href=
"../reference/api/org/eclipse/jdt/core/ITypeRoot.html#getWorkingCopy(org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
getWorkingCopy(WorkingCopyOwner, IProgressMonitor)</a></b> method. Clients can manipulate the text
of this buffer directly. If they do so, they must synchronize the working copy with the buffer from
time to time using either the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</a></b> method.</p>
<p>Finally a working copy can be saved to disk (replacing the original compilation unit) using the
<b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#commitWorkingCopy(boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
commitWorkingCopy</a></b> method.&nbsp;&nbsp;</p>
<p>For example the following code snippet creates a working copy on a compilation unit using a
custom working copy owner. The snippet modifies the buffer, reconciles the changes, commits the
changes to disk and finally discards the working copy.</p>
<pre class="color1">
// Get original compilation unit
ICompilationUnit originalUnit = ...;
// Get working copy owner
WorkingCopyOwner owner = ...;
// Create working copy
ICompilationUnit workingCopy = originalUnit.getWorkingCopy(owner, null);
// Modify buffer and reconcile
IBuffer buffer = ((IOpenable)workingCopy).getBuffer();
buffer.append("class X {}");
workingCopy.reconcile(ICompilationUnit.NO_AST, false, null, null);
// Commit changes
workingCopy.commitWorkingCopy(false, null);
// Destroy working copy
workingCopy.discardWorkingCopy();
</pre>
<p>The compilation unit's buffer can also be modified using the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#applyTextEdit(org.eclipse.text.edits.TextEdit,%20org.eclipse.core.runtime.IProgressMonitor)">
ICompilationUnit.applyTextEdit</a></b> method.</p>
<pre class="color1">
// Get original compilation unit
ICompilationUnit originalUnit = ...;
// Get working copy owner
WorkingCopyOwner owner = ...;
// Create working copy
ICompilationUnit workingCopy = originalUnit.getWorkingCopy(owner, null);
// Get text edits
TextEdit edit = ...;
// Modify buffer and reconcile
workingCopy.applyTextEdit(edit, null);
workingCopy.reconcile(ICompilationUnit.NO_AST, false, null, null);
// Commit changes
workingCopy.commitWorkingCopy(false, null);
// Destroy working copy
workingCopy.discardWorkingCopy();
</pre>
<p>Working copies can also be shared by several clients using a working copy owner. A working copy
can be later retrieved using the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#findWorkingCopy(org.eclipse.jdt.core.WorkingCopyOwner)">
findWorkingCopy</a></b> method. A shared working copy is thus keyed on the original compilation
unit and on a working copy owner.</p>
<p>The following shows how client 1 creates a shared working copy, client 2 retrieves this working
copy, client 1 discards the working copy, and client 2 trying to retrieve the shared working copy
notices it does not exist any longer:</p>
<pre class="color1">
// Client 1 &amp; 2: Get original compilation unit
ICompilationUnit originalUnit = ...;
// Client 1 &amp; 2: Get working copy owner
WorkingCopyOwner owner = ...;
// Client 1: Create shared working copy
ICompilationUnit workingCopyForClient1 = originalUnit.getWorkingCopy(owner, null);
// Client 2: Retrieve shared working copy
ICompilationUnit workingCopyForClient2 = originalUnit.findWorkingCopy(owner);
// This is the same working copy
assert workingCopyForClient1 == workingCopyForClient2;
// Client 1: Discard shared working copy
workingCopyForClient1.discardWorkingCopy();
// Client 2: Attempt to retrieve shared working copy and find out it's null
workingCopyForClient2 = originalUnit.findWorkingCopy(owner);
assert workingCopyForClient2 == null;
</pre>
<h3>Code modification using the DOM/AST API</h3>
There are three ways to create a <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html">CompilationUnit</a></b>. The first
one is to use <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b>. The second is to use
<b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
ICompilationUnit#reconcile(...)</a></b>. The third is to start from scratch using the factory
methods on <b><a href="../reference/api/org/eclipse/jdt/core/dom/AST.html">AST</a></b> (Abstract
Syntax Tree).
<h4>Creating an AST from existing source code</h4>
An instance of <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b> must be created with
<b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#newParser(int)">ASTParser.newParser(int)</a></b>.<br />
<br />
The source code is given to the <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html">ASTParser</a></b> with one of the
following methods:
<ul>
<li><b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(char[])">setSource(char[])</a></b>:
to create the AST from source code</li>
<li><b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(org.eclipse.jdt.core.IClassFile)">
setSource(IClassFile)</a></b>: to create the AST from a classfile</li>
<li><b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setSource(org.eclipse.jdt.core.ICompilationUnit)">
setSource(ICompilationUnit)</a></b>: to create the AST from a compilation unit</li>
</ul>
Then the AST is created by calling <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#createAST(org.eclipse.core.runtime.IProgressMonitor)">
createAST(IProgressMonitor)</a></b>.<br />
<br />
The result is an AST with correct source positions for each node. The resolution of bindings has to
be requested before the creation of the tree with <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setResolveBindings(boolean)">setResolveBindings(boolean)</a></b>.
Resolving the bindings is a costly operation and should be done only when necessary. As soon as the
tree has been modified, all positions and bindings are lost.<br />
Note that some bindings recovery can also be done during this resolution with <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/ASTParser.html#setBindingsRecovery(boolean)">setBindingsRecovery(boolean)</a></b>.
Using this recovery, some bindings - <i>typically missing types</i> - will no longer be
<code>null</code>, hence improving the resilience of any clients using the AST tree.
<h4>Creating an AST by reconciling a working copy</h4>
If a working copy is not consistent (has been modified) then an AST can be created by calling the
method <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</a></b>. To request AST creation, call
the <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
reconcile(...)</a></b> method with <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/AST.html#JLS3">AST.JLS3</a></b> as first
parameter.<br />
<br />
Its bindings are computed only if the problem requestor is active, or if the problem detection is
forced. Resolving the bindings is a costly operation and should be done only when necessary. As
soon as the tree has been modified, all positions and bindings are lost.<br />
Note that some bindings recovery can also be done during this resolution with by using the method
<b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20int,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
reconcile(int, int, WorkingCopyOwner, IProgressMonitor)</a></b> with the flag <b><a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#ENABLE_BINDINGS_RECOVERY">ENABLE_BINDINGS_RECOVERY</a></b>
set on the second parameter. Using this recovery, some bindings - <i>typically missing types</i> -
will no longer be <code>null</code>, hence improving the resilience of any clients using the AST
tree.
<h4>From scratch</h4>
<p>It is possible to create a <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html">CompilationUnit</a></b> from
scratch using the factory methods on <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/AST.html">AST</a></b>. These method names start with
<b>new...</b>. The following is an example that creates a <b>HelloWorld</b> class.</p>
<p>The first snippet is the generated output:</p>
<pre class="color1">
package example;
import java.util.*;
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello" + " world");
}
}
</pre>
<p>The following snippet is the corresponding code that generates the output.</p>
<pre class="color1">
AST ast = AST.newAST(AST.JLS3);
CompilationUnit unit = ast.newCompilationUnit();
PackageDeclaration packageDeclaration = ast.newPackageDeclaration();
packageDeclaration.setName(ast.newSimpleName("example"));
unit.setPackage(packageDeclaration);
ImportDeclaration importDeclaration = ast.newImportDeclaration();
QualifiedName name =
ast.newQualifiedName(
ast.newSimpleName("java"),
ast.newSimpleName("util"));
importDeclaration.setName(name);
importDeclaration.setOnDemand(true);
unit.imports().add(importDeclaration);
TypeDeclaration type = ast.newTypeDeclaration();
type.setInterface(false);
type.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
type.setName(ast.newSimpleName("HelloWorld"));
MethodDeclaration methodDeclaration = ast.newMethodDeclaration();
methodDeclaration.setConstructor(false);
List modifiers = methodDeclaration.modifiers();
modifiers.add(ast.newModifier(Modifier.ModifierKeyword.PUBLIC_KEYWORD));
modifiers.add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
methodDeclaration.setName(ast.newSimpleName("main"));
methodDeclaration.setReturnType2(ast.newPrimitiveType(PrimitiveType.VOID));
SingleVariableDeclaration variableDeclaration = ast.newSingleVariableDeclaration();
variableDeclaration.setType(ast.newArrayType(ast.newSimpleType(ast.newSimpleName("String"))));
variableDeclaration.setName(ast.newSimpleName("args"));
methodDeclaration.parameters().add(variableDeclaration);
org.eclipse.jdt.core.dom.Block block = ast.newBlock();
MethodInvocation methodInvocation = ast.newMethodInvocation();
name =
ast.newQualifiedName(
ast.newSimpleName("System"),
ast.newSimpleName("out"));
methodInvocation.setExpression(name);
methodInvocation.setName(ast.newSimpleName("println"));
InfixExpression infixExpression = ast.newInfixExpression();
infixExpression.setOperator(InfixExpression.Operator.PLUS);
StringLiteral literal = ast.newStringLiteral();
literal.setLiteralValue("Hello");
infixExpression.setLeftOperand(literal);
literal = ast.newStringLiteral();
literal.setLiteralValue(" world");
infixExpression.setRightOperand(literal);
methodInvocation.arguments().add(infixExpression);
ExpressionStatement expressionStatement = ast.newExpressionStatement(methodInvocation);
block.statements().add(expressionStatement);
methodDeclaration.setBody(block);
type.bodyDeclarations().add(methodDeclaration);
unit.types().add(type);
</pre>
<h4>Retrieving extra positions</h4>
<p>The DOM/AST node contains only a pair of positions (the starting position and the length of the
node). This is not always sufficient. In order to retrieve intermediate positions, the <b><a href=
"../reference/api/org/eclipse/jdt/core/compiler/IScanner.html">IScanner</a></b> API should be used.
For example, we have an <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/InstanceofExpression.html">InstanceofExpression</a></b>
for which we want to know the positions of the <i>instanceof</i> operator. We could write the
following method to achieve this:</p>
<pre class="color1">
private int[] getOperatorPosition(Expression expression, char[] source) {
if (expression instanceof InstanceofExpression) {
IScanner scanner = ToolFactory.createScanner(false, false, false, false);
scanner.setSource(source);
int start = expression.getStartPosition();
int end = start + expression.getLength();
scanner.resetTo(start, end);
int token;
try {
while ((token = scanner.getNextToken()) != ITerminalSymbols.TokenNameEOF) {
switch(token) {
case ITerminalSymbols.TokenNameinstanceof:
return new int[] {scanner.getCurrentTokenStartPosition(), scanner.getCurrentTokenEndPosition()};
}
}
} catch (InvalidInputException e) {
}
}
return null;
}
</pre>
<p>The <b><a href="../reference/api/org/eclipse/jdt/core/compiler/IScanner.html">IScanner</a></b>
is used to divide the input source into tokens. Each token has a specific value that is defined in
the <b><a href=
"../reference/api/org/eclipse/jdt/core/compiler/ITerminalSymbols.html">ITerminalSymbols</a></b>
interface. It is fairly simple to iterate and retrieve the right token. We also recommend that you
use the scanner if you want to find the position of the <i>super</i> keyword in a <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/SuperMethodInvocation.html">SuperMethodInvocation</a></b>.</p>
<h4>Source code modifications</h4>
<p>Some source code modifications are not provided via the Java element API. A more general way to
edit source code (such as changing the source code for existing elements) is accomplished using the
compilation unit's raw source code and the rewrite API of the DOM/AST.</p>
<p>To perform DOM/AST rewriting, there are two sets of API: the descriptive rewriting and the
modifying rewriting.</p>
<p>The descriptive API does not modify the AST but use <b><a href=
"../reference/api/org/eclipse/jdt/core/dom/rewrite/ASTRewrite.html">ASTRewrite</a></b> API to
generate the descriptions of modifications. The AST rewriter collects descriptions of modifications
to nodes and translates these descriptions into text edits that can then be applied to the original
source.</p>
<pre class="color1">
// creation of a Document
ICompilationUnit cu = ... ; // content is "public class X {\n}"
String source = cu.getSource();
Document document= new Document(source);
// creation of DOM/AST from a ICompilationUnit
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(cu);
CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
// creation of ASTRewrite
ASTRewrite rewrite = ASTRewrite.create(astRoot.getAST());
// description of the change
SimpleName oldName = ((TypeDeclaration)astRoot.types().get(0)).getName();
SimpleName newName = astRoot.getAST().newSimpleName("Y");
rewrite.replace(oldName, newName, null);
// computation of the text edits
TextEdit edits = rewrite.rewriteAST(document, cu.getJavaProject().getOptions(true));
// computation of the new source code
edits.apply(document);
String newSource = document.get();
// update of the compilation unit
cu.getBuffer().setContents(newSource);
</pre>
<p>The modifying API allows to modify directly the AST:</p>
<ul>
<li>Request the recording of modifications (<b><a href=
"../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html#recordModifications()">CompilationUnit.recordModifications()</a></b>).</li>
<li>Perform the modifications on the AST Nodes.</li>
<li>And when the modifications are finished, generate text edits that can then be applied to the
original source (<b><a href=
"../reference/api/org/eclipse/jdt/core/dom/CompilationUnit.html#rewrite(org.eclipse.jface.text.IDocument,%20java.util.Map)">CompilationUnit.rewrite(...)</a></b>).</li>
</ul>
<pre class="color1">
// creation of a Document
ICompilationUnit cu = ... ; // content is "public class X {\n}"
String source = cu.getSource();
Document document= new Document(source);
// creation of DOM/AST from a ICompilationUnit
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(cu);
CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);
// start record of the modifications
astRoot.recordModifications();
// modify the AST
TypeDeclaration typeDeclaration = (TypeDeclaration)astRoot.types().get(0);
SimpleName newName = astRoot.getAST().newSimpleName("Y");
typeDeclaration.setName(newName);
// computation of the text edits
TextEdit edits = astRoot.rewrite(document, cu.getJavaProject().getOptions(true));
// computation of the new source code
edits.apply(document);
String newSource = document.get();
// update of the compilation unit
cu.getBuffer().setContents(newSource);
</pre>
<h3><a name="javadeltas" id="javadeltas">Responding to changes in Java elements</a></h3>
<p>If your plug-in needs to know about changes to Java elements after the fact, you can register a
Java <a href=
"../reference/api/org/eclipse/jdt/core/IElementChangedListener.html"><b>IElementChangedListener</b></a>
with <a href="../reference/api/org/eclipse/jdt/core/JavaCore.html"><b>JavaCore</b></a>.</p>
<pre class="color1">
JavaCore.addElementChangedListener(new MyJavaElementChangeReporter());
</pre>
<p>You can be more specific and specify the type of events you're interested in using <a href=
"../reference/api/org/eclipse/jdt/core/JavaCore.html#addElementChangedListener(org.eclipse.jdt.core.IElementChangedListener,%20int)">
<b>addElementChangedListener(IElementChangedListener, int)</b></a>.</p>
<p>For example, if you're only interested in listening for events during a reconcile operation:</p>
<pre class="color1">
JavaCore.addElementChangedListener(new MyJavaElementChangeReporter(), ElementChangedEvent.POST_RECONCILE);
</pre>
<p>There are two kinds of events that are supported by <b>JavaCore</b>:</p>
<ul>
<li><a href=
"../reference/api/org/eclipse/jdt/core/ElementChangedEvent.html#POST_CHANGE"><b>POST_CHANGE</b></a>:
Listeners of this event kind will get notified during the corresponding <a href=
"../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IResourceChangeEvent.html#POST_CHANGE">
<b>POST_CHANGE</b></a> resource change notification.</li>
<li><a href=
"../reference/api/org/eclipse/jdt/core/ElementChangedEvent.html#POST_RECONCILE"><b>POST_RECONCILE</b></a>:
Listeners of this event kind will get notified at the end of a reconcile operation on a working
copy (see <a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>ICompilationUnit.reconcile(int, boolean, WorkingCopyOwner, IProgressMonitor)</b></a>).</li>
</ul>
<p>Java element change listeners are similar conceptually to resource change listeners (described
in <a href="../../org.eclipse.platform.doc.isv/guide/resAdv_events.htm" class="XRef">tracking
resource changes</a>). The following snippet implements a Java element change reporter that prints
the element deltas to the system console.</p>
<pre class="color1">
public class MyJavaElementChangeReporter implements IElementChangedListener {
public void elementChanged(ElementChangedEvent event) {
IJavaElementDelta delta= event.getDelta();
if (delta != null) {
System.out.println("delta received: ");
System.out.print(delta);
}
}
}
</pre>
<p>The <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html"><b>IJavaElementDelta</b></a>
includes the <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getElement()">element</a> that was
changed and <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getFlags()">flags</a> describing the
kind of change that occurred. Most of the time the delta tree is rooted at the Java Model level.
Clients must then navigate this delta using <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAffectedChildren()"><b>getAffectedChildren</b></a>
to find out what projects have changed.</p>
<p>The following example method traverses a delta and prints the elements that have been added,
removed and changed:</p>
<pre class="color1">
void traverseAndPrint(IJavaElementDelta delta) {
switch (delta.getKind()) {
case IJavaElementDelta.ADDED:
System.out.println(delta.getElement() + " was added");
break;
case IJavaElementDelta.REMOVED:
System.out.println(delta.getElement() + " was removed");
break;
case IJavaElementDelta.CHANGED:
System.out.println(delta.getElement() + " was changed");
if ((delta.getFlags() &amp; IJavaElementDelta.F_CHILDREN) != 0) {
System.out.println("The change was in its children");
}
if ((delta.getFlags() &amp; IJavaElementDelta.F_CONTENT) != 0) {
System.out.println("The change was in its content");
}
/* Others flags can also be checked */
break;
}
IJavaElementDelta[] children = delta.getAffectedChildren();
for (int i = 0; i &lt; children.length; i++) {
traverseAndPrint(children[i]);
}
}
</pre>
<p>Since <a href="../reference/api/org/eclipse/jdt/core/IAnnotation.html"><b>IAnnotation</b></a>s
are not children of any Java element, annotation deltas are obtained using <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAnnotationDeltas()"><b>getAnnotationDeltas()</b></a>.</p>
<p>Several kinds of operations can trigger a Java element change notification. Here are some
examples:</p>
<ul>
<li>Creating a resource, e.g. <a href=
"../reference/api/org/eclipse/jdt/core/IPackageFragment.html#createCompilationUnit(java.lang.String,%20java.lang.String,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>IPackageFragment.createCompilationUnit</b></a> (the delta indicates the <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#ADDED">addition</a> of the
compilation unit)</li>
<li>Modifying a resource, e.g. <a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#createType(java.lang.String,%20org.eclipse.jdt.core.IJavaElement,%20boolean,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>ICompilationUnit.createType</b></a> (the delta indicates that the compilation unit has <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#CHANGED">changed</a> and that a type
was <a href="../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#getAddedChildren()">added
as a child</a> of this compilation unit)</li>
<li>Modifying a project's classpath, e.g. <a href=
"../reference/api/org/eclipse/jdt/core/IJavaProject.html#setRawClasspath(org.eclipse.jdt.core.IClasspathEntry[],%20org.eclipse.core.runtime.IProgressMonitor)">
<b>IJavaProject.setRawClasspath</b></a> (the delta indicates that package fragment roots have been
<a href="../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_ADDED_TO_CLASSPATH">added
to the classpath</a>, <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_REMOVED_FROM_CLASSPATH">removed
from the classpath</a>, or <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_CLASSPATH_REORDER">reordered on the
classpath</a>)</li>
<li>Modifying a classpath variable value, e.g. <a href=
"../reference/api/org/eclipse/jdt/core/JavaCore.html#setClasspathVariable(java.lang.String,%20org.eclipse.core.runtime.IPath,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>JavaCore.setClasspathVariable</b></a> (the delta also indicates that package fragment roots have
been affected)</li>
<li>Reconciling a working copy with its buffer, e.g. <a href=
"../reference/api/org/eclipse/jdt/core/ICompilationUnit.html#reconcile(int,%20boolean,%20org.eclipse.jdt.core.WorkingCopyOwner,%20org.eclipse.core.runtime.IProgressMonitor)">
<b>ICompilationUnit.reconcile</b></a></li>
<li>Modifying an <a href=
"../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IFile.html"><b>IFile</b></a>
that ends with ".java" and that is on the project's classpath, e.g. using <b>IFile.setContents</b>
(the delta indicates that a compilation unit was changed, but <a href=
"../reference/api/org/eclipse/jdt/core/IJavaElementDelta.html#F_FINE_GRAINED">no finer-grained
information</a> is provided as this was not done through a Java Model operation)</li>
</ul>
<p>Similar to <a href=
"../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IResourceDelta.html"><b>
IResourceDelta</b></a> the Java element deltas can be batched using an <a href=
"../../org.eclipse.platform.doc.isv/reference/api/org/eclipse/core/resources/IWorkspaceRunnable.html">
<b>IWorkspaceRunnable</b></a>. The deltas resulting from several Java Model operations that are run
inside a <b>IWorkspaceRunnable</b> are merged and reported at once.&nbsp;&nbsp;</p>
<p><a href="../reference/api/org/eclipse/jdt/core/JavaCore.html"><b>JavaCore</b></a>provides a
<b>run</b> method for batching Java element changes.</p>
<p>For example, the following code fragment will trigger 2 Java element change events:</p>
<pre class="color1">
// Get package
IPackageFragment pkg = ...;
// Create 2 compilation units
ICompilationUnit unitA = pkg.createCompilationUnit("A.java", "public class A {}", false, null);
ICompilationUnit unitB = pkg.createCompilationUnit("B.java", "public class B {}", false, null);
</pre>
<p>Whereas the following code fragment will trigger 1 Java element change event:</p>
<pre class="color1">
// Get package
final IPackageFragment pkg = ...;
// Create 2 compilation units
JavaCore.run(
new IWorkspaceRunnable() {
public void run(IProgressMonitor monitor) throws CoreException {
ICompilationUnit unitA = pkg.createCompilationUnit("A.java", "public class A {}", false, null);
ICompilationUnit unitB = pkg.createCompilationUnit("B.java", "public class B {}", false, null);
}
},
null);
</pre>
</body>
</html>